Merge tag 'imx-drm-next-2015-03-31' of git://git.pengutronix.de/git/pza/linux into...
authorDave Airlie <airlied@redhat.com>
Mon, 13 Apr 2015 07:28:57 +0000 (17:28 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 13 Apr 2015 07:28:57 +0000 (17:28 +1000)
imx-drm changes to use media bus formats and LDB drm_panel support

- Add media bus formats needed by imx-drm
- Switch to use media bus formats to describe the pixel format
  on the internal parallel bus between display interface and
  encoders
- Some preparations for TV Output via TVEv2 on i.MX5
- Add drm_panel support to the i.MX LVDS driver, allow to
  determine the bus pixel format from the panel descriptor.

* tag 'imx-drm-next-2015-03-31' of git://git.pengutronix.de/git/pza/linux:
  drm/imx: imx-ldb: allow to determine bus format from the connected panel
  drm/imx: imx-ldb: reset display clock input when disabling LVDS
  drm/imx: imx-ldb: add drm_panel support
  drm/imx: consolidate bus format variable names
  drm/imx: switch to use media bus formats
  Add RGB666_1X24_CPADHI media bus format
  Add YUV8_1X24 media bus format
  Add BGR888_1X24 and GBR888_1X24 media bus formats
  Add LVDS RGB media bus formats
  Add RGB444_1X12 and RGB565_1X16 media bus formats
  drm/imx: ipuv3-crtc: Allow to divide DI clock from TVEv2
  drm/imx: Add support for interlaced scanout

741 files changed:
Documentation/DocBook/drm.tmpl
Documentation/devicetree/bindings/arm/bcm/brcm,bcm11351-cpu-method.txt [moved from Documentation/devicetree/bindings/arm/bcm/brcm,bcm11351-cpu-method with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm11351.txt [moved from Documentation/devicetree/bindings/arm/bcm/bcm11351.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm21664.txt [moved from Documentation/devicetree/bindings/arm/bcm/bcm21664.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt [moved from Documentation/devicetree/bindings/arm/bcm2835.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.txt [moved from Documentation/devicetree/bindings/arm/bcm4708.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm63138.txt [moved from Documentation/devicetree/bindings/arm/bcm/bcm63138.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt [moved from Documentation/devicetree/bindings/arm/brcm-brcmstb.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,cygnus.txt [moved from Documentation/devicetree/bindings/arm/bcm/cygnus.txt with 100% similarity]
Documentation/devicetree/bindings/bus/brcm,bus-axi.txt [moved from Documentation/devicetree/bindings/bus/bcma.txt with 100% similarity]
Documentation/devicetree/bindings/clock/brcm,kona-ccu.txt [moved from Documentation/devicetree/bindings/clock/bcm-kona-clock.txt with 100% similarity]
Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt [moved from Documentation/devicetree/bindings/dma/bcm2835-dma.txt with 100% similarity]
Documentation/devicetree/bindings/gpio/brcm,kona-gpio.txt [moved from Documentation/devicetree/bindings/gpio/gpio-bcm-kona.txt with 100% similarity]
Documentation/devicetree/bindings/i2c/brcm,kona-i2c.txt [moved from Documentation/devicetree/bindings/i2c/i2c-bcm-kona.txt with 100% similarity]
Documentation/devicetree/bindings/mfd/brcm,bcm59056.txt [moved from Documentation/devicetree/bindings/mfd/bcm590xx.txt with 100% similarity]
Documentation/devicetree/bindings/mips/brcm/brcm,bcm3384-intc.txt [moved from Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt with 100% similarity]
Documentation/devicetree/bindings/mips/brcm/brcm,bmips.txt [moved from Documentation/devicetree/bindings/mips/brcm/bmips.txt with 100% similarity]
Documentation/devicetree/bindings/mips/brcm/brcm,cm-dsl.txt [moved from Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt with 100% similarity]
Documentation/devicetree/bindings/misc/brcm,kona-smc.txt [moved from Documentation/devicetree/bindings/misc/smc.txt with 100% similarity]
Documentation/devicetree/bindings/mmc/brcm,kona-sdhci.txt [moved from Documentation/devicetree/bindings/mmc/kona-sdhci.txt with 100% similarity]
Documentation/devicetree/bindings/net/brcm,bcm7445-switch-v4.0.txt [moved from Documentation/devicetree/bindings/net/broadcom-sf2.txt with 100% similarity]
Documentation/devicetree/bindings/net/brcm,bcmgenet.txt [moved from Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt with 100% similarity]
Documentation/devicetree/bindings/net/brcm,systemport.txt [moved from Documentation/devicetree/bindings/net/broadcom-systemport.txt with 100% similarity]
Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt [moved from Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt with 100% similarity]
Documentation/devicetree/bindings/net/dsa/dsa.txt
Documentation/devicetree/bindings/panel/ampire,am800480r3tmqwa1h.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/auo,b101ean01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/innolux,at043tn24.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/innolux,zj070na-01p.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/ortustech,com43h4m85ulc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/samsung,ltn140at29-301.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/shelly,sca07010-bfn-lnn.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/brcm,kona-usb2-phy.txt [moved from Documentation/devicetree/bindings/phy/bcm-phy.txt with 100% similarity]
Documentation/devicetree/bindings/pwm/brcm,kona-pwm.txt [moved from Documentation/devicetree/bindings/pwm/bcm-kona-pwm.txt with 100% similarity]
Documentation/devicetree/bindings/reset/brcm,bcm21664-resetmgr.txt [moved from Documentation/devicetree/bindings/arm/bcm/kona-resetmgr.txt with 100% similarity]
Documentation/devicetree/bindings/serial/brcm,bcm6345-uart.txt [moved from Documentation/devicetree/bindings/serial/bcm63xx-uart.txt with 100% similarity]
Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt [moved from Documentation/devicetree/bindings/sound/bcm2835-i2s.txt with 100% similarity]
Documentation/devicetree/bindings/timer/brcm,kona-timer.txt [moved from Documentation/devicetree/bindings/arm/bcm/kona-timer.txt with 100% similarity]
Documentation/devicetree/bindings/unittest.txt
Documentation/devicetree/bindings/usb/brcm,bcm3384-usb.txt [moved from Documentation/devicetree/bindings/mips/brcm/usb.txt with 100% similarity]
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/devicetree/bindings/watchdog/brcm,kona-wdt.txt [moved from Documentation/devicetree/bindings/arm/bcm/kona-wdt.txt with 100% similarity]
Documentation/devicetree/of_unittest.txt [moved from Documentation/devicetree/of_selftest.txt with 90% similarity]
Documentation/input/alps.txt
Documentation/input/event-codes.txt
Documentation/input/multi-touch-protocol.txt
MAINTAINERS
Makefile
arch/arc/kernel/signal.c
arch/arm/Kconfig
arch/arm/boot/dts/dm8168-evm.dts
arch/arm/boot/dts/dm816x.dtsi
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/rk3288.dtsi
arch/arm/boot/dts/socfpga.dtsi
arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
arch/arm/boot/dts/sun4i-a10.dtsi
arch/arm/boot/dts/sun5i-a13.dtsi
arch/arm/boot/dts/sun7i-a20.dtsi
arch/arm/crypto/aesbs-core.S_shipped
arch/arm/crypto/bsaes-armv7.pl
arch/arm/include/asm/kvm_mmu.h
arch/arm/kernel/setup.c
arch/arm/kvm/mmu.c
arch/arm/mach-omap2/id.c
arch/arm/mach-pxa/irq.c
arch/arm/mach-pxa/zeus.c
arch/arm/mach-sunxi/Kconfig
arch/arm/mm/cache-l2x0.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/fault.c
arch/arm/mm/pageattr.c
arch/arm/plat-omap/dmtimer.c
arch/arm64/boot/dts/arm/juno-clocks.dtsi
arch/arm64/include/asm/cmpxchg.h
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/percpu.h
arch/arm64/include/asm/proc-fns.h
arch/arm64/kernel/efi.c
arch/arm64/mm/dma-mapping.c
arch/metag/include/asm/io.h
arch/metag/include/asm/pgtable-bits.h [new file with mode: 0644]
arch/metag/include/asm/pgtable.h
arch/nios2/include/uapi/asm/Kbuild
arch/nios2/mm/fault.c
arch/parisc/include/asm/pgalloc.h
arch/parisc/kernel/syscall_table.S
arch/powerpc/include/asm/cputhreads.h
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/reg.h
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dbell.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/platforms/powernv/smp.c
arch/powerpc/platforms/pseries/mobility.c
arch/s390/include/asm/elf.h
arch/s390/kernel/ftrace.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/swsusp_asm64.S
arch/s390/kvm/kvm-s390.c
arch/sparc/Kconfig
arch/sparc/include/asm/hypervisor.h
arch/sparc/include/asm/io_64.h
arch/sparc/include/asm/starfire.h
arch/sparc/kernel/entry.h
arch/sparc/kernel/hvapi.c
arch/sparc/kernel/hvcalls.S
arch/sparc/kernel/pcr.c
arch/sparc/kernel/perf_event.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/starfire.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/traps_64.c
arch/sparc/lib/memmove.S
arch/sparc/mm/init_64.c
arch/x86/boot/compressed/aslr.c
arch/x86/boot/compressed/misc.c
arch/x86/boot/compressed/misc.h
arch/x86/crypto/aesni-intel_glue.c
arch/x86/include/asm/fpu-internal.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/uapi/asm/bootparam.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/apic_numachip.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/kgdb.c
arch/x86/kernel/module.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/traps.c
arch/x86/kernel/xsave.c
arch/x86/kvm/i8259.c
arch/x86/kvm/ioapic.c
arch/x86/kvm/lapic.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/pci/common.c
arch/x86/pci/intel_mid_pci.c
arch/x86/pci/irq.c
arch/x86/vdso/vdso32/sigreturn.S
arch/x86/xen/p2m.c
block/blk-merge.c
block/blk-mq-tag.c
block/blk-mq.c
block/blk-settings.c
drivers/acpi/pci_irq.c
drivers/ata/libata-core.c
drivers/base/regmap/internal.h
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
drivers/block/nbd.c
drivers/block/nvme-core.c
drivers/char/virtio_console.c
drivers/clocksource/Kconfig
drivers/clocksource/time-efm32.c
drivers/clocksource/timer-sun5i.c
drivers/coresight/of_coresight.c
drivers/cpuidle/cpuidle-mvebu-v7.c
drivers/dma/amba-pl08x.c
drivers/dma/at_hdmac.c
drivers/dma/at_hdmac_regs.h
drivers/dma/bcm2835-dma.c
drivers/dma/dma-jz4740.c
drivers/dma/dw/platform.c
drivers/dma/edma.c
drivers/dma/imx-sdma.c
drivers/dma/moxart-dma.c
drivers/dma/omap-dma.c
drivers/firmware/dmi_scan.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-syscon.c
drivers/gpio/gpiolib-acpi.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
drivers/gpu/drm/bochs/bochs_hw.c
drivers/gpu/drm/bridge/Kconfig
drivers/gpu/drm/bridge/Makefile
drivers/gpu/drm/bridge/ps8622.c [new file with mode: 0644]
drivers/gpu/drm/bridge/ptn3460.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_edid_load.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_of.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos7_drm_decon.c
drivers/gpu/drm/exynos/exynos_dp_core.c
drivers/gpu/drm/exynos/exynos_drm_connector.c [deleted file]
drivers/gpu/drm/exynos/exynos_drm_connector.h [deleted file]
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_crtc.h
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_fimd.h [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_drm_plane.h
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/exynos/regs-mixer.h
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_evict.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_gtt.h
drivers/gpu/drm/i915/i915_gem_shrinker.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_trace.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_dp_mst.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dsi.c
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_fbc.c
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_frontbuffer.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_psr.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/imx/imx-drm-core.c
drivers/gpu/drm/msm/Kconfig
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/dsi/dsi.c [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/dsi.h [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/dsi.xml.h
drivers/gpu/drm/msm/dsi/dsi_host.c [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/dsi_manager.c [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/dsi_phy.c [new file with mode: 0644]
drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_fbdev.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem.h
drivers/gpu/drm/msm/msm_kms.h
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c
drivers/gpu/drm/omapdrm/omap_connector.c
drivers/gpu/drm/omapdrm/omap_crtc.c
drivers/gpu/drm/omapdrm/omap_dmm_priv.h
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
drivers/gpu/drm/omapdrm/omap_dmm_tiler.h
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/omapdrm/omap_drv.h
drivers/gpu/drm/omapdrm/omap_fb.c
drivers/gpu/drm/omapdrm/omap_fbdev.c
drivers/gpu/drm/omapdrm/omap_gem.c
drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
drivers/gpu/drm/omapdrm/omap_irq.c
drivers/gpu/drm/omapdrm/omap_plane.c
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_bios.c
drivers/gpu/drm/radeon/radeon_kfd.c
drivers/gpu/drm/radeon/radeon_mn.c
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_ttm.c
drivers/gpu/drm/radeon/vce_v2_0.c
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.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/hdmi.c
drivers/gpu/drm/tegra/hdmi.h
drivers/gpu/drm/tegra/sor.c
drivers/gpu/drm/vgem/Makefile [new file with mode: 0644]
drivers/gpu/drm/vgem/vgem_dma_buf.c [new file with mode: 0644]
drivers/gpu/drm/vgem/vgem_drv.c [new file with mode: 0644]
drivers/gpu/drm/vgem/vgem_drv.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/host1x/syncpt.c
drivers/gpu/ipu-v3/ipu-di.c
drivers/gpu/ipu-v3/ipu-ic.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-tivo.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_wac.c
drivers/ide/ide-tape.c
drivers/iio/accel/bma180.c
drivers/iio/accel/bmc150-accel.c
drivers/iio/accel/kxcjk-1013.c
drivers/iio/adc/Kconfig
drivers/iio/adc/at91_adc.c
drivers/iio/adc/ti_am335x_adc.c
drivers/iio/adc/vf610_adc.c
drivers/iio/gyro/bmg160.c
drivers/iio/imu/adis_trigger.c
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
drivers/iio/imu/kmx61.c
drivers/iio/industrialio-core.c
drivers/iio/industrialio-event.c
drivers/iio/proximity/sx9500.c
drivers/infiniband/core/umem.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/input/mouse/alps.c
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.h
drivers/iommu/arm-smmu.c
drivers/iommu/intel-iommu.c
drivers/iommu/ipmmu-vmsa.c
drivers/irqchip/irq-gic-v3-its.c
drivers/isdn/icn/icn.c
drivers/lguest/Kconfig
drivers/md/dm-io.c
drivers/md/dm-snap.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/raid0.c
drivers/media/platform/am437x/am437x-vpfe.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/mfd/kempld-core.c
drivers/mfd/rtsx_usb.c
drivers/mmc/core/pwrseq_simple.c
drivers/mtd/ubi/eba.c
drivers/net/bonding/bond_main.c
drivers/net/can/Kconfig
drivers/net/can/flexcan.c
drivers/net/can/usb/gs_usb.c
drivers/net/can/usb/kvaser_usb.c
drivers/net/can/usb/peak_usb/pcan_ucan.h
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
drivers/net/ethernet/amd/pcnet32.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
drivers/net/ethernet/dec/tulip/tulip_core.c
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/rocker/rocker.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/wiznet/w5100.c
drivers/net/ethernet/wiznet/w5300.c
drivers/net/ipvlan/ipvlan.h
drivers/net/ipvlan/ipvlan_core.c
drivers/net/ipvlan/ipvlan_main.c
drivers/net/usb/asix_common.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/cx82310_eth.c
drivers/net/usb/r8152.c
drivers/net/usb/sr9800.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/brcm80211/brcmfmac/feature.c
drivers/net/wireless/brcm80211/brcmfmac/vendor.c
drivers/net/wireless/iwlwifi/dvm/dev.h
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/ucode.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netfront.c
drivers/of/Makefile
drivers/of/address.c
drivers/of/base.c
drivers/of/irq.c
drivers/of/unittest-data/.gitignore [new file with mode: 0644]
drivers/of/unittest-data/Makefile [new file with mode: 0644]
drivers/of/unittest-data/tests-overlay.dtsi
drivers/of/unittest.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/rsrc_pci.c [deleted file]
drivers/phy/phy-armada375-usb2.c
drivers/phy/phy-core.c
drivers/phy/phy-exynos-dp-video.c
drivers/phy/phy-exynos-mipi-video.c
drivers/phy/phy-exynos4210-usb2.c
drivers/phy/phy-exynos4x12-usb2.c
drivers/phy/phy-exynos5-usbdrd.c
drivers/phy/phy-exynos5250-usb2.c
drivers/phy/phy-hix5hd2-sata.c
drivers/phy/phy-miphy28lp.c
drivers/phy/phy-miphy365x.c
drivers/phy/phy-omap-control.c
drivers/phy/phy-omap-usb2.c
drivers/phy/phy-rockchip-usb.c
drivers/phy/phy-ti-pipe3.c
drivers/phy/phy-twl4030-usb.c
drivers/phy/phy-xgene.c
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/pinctrl/sunxi/pinctrl-sunxi.h
drivers/powercap/intel_rapl.c
drivers/regulator/core.c
drivers/regulator/palmas-regulator.c
drivers/regulator/tps65910-regulator.c
drivers/rpmsg/virtio_rpmsg_bus.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-mrst.c
drivers/scsi/ipr.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/spi/spi-dw-mid.c
drivers/spi/spi-qup.c
drivers/spi/spi.c
drivers/staging/iio/Kconfig
drivers/staging/iio/magnetometer/hmc5843_core.c
drivers/staging/vt6655/device_main.c
drivers/staging/vt6655/rf.c
drivers/staging/vt6656/rf.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_erl0.c
drivers/target/loopback/tcm_loop.c
drivers/target/target_core_device.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tfc_io.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/samsung.c
drivers/usb/chipidea/udc.c
drivers/usb/common/usb-otg-fsm.c
drivers/usb/dwc2/core_intr.c
drivers/usb/gadget/function/f_loopback.c
drivers/usb/gadget/function/f_sourcesink.c
drivers/usb/gadget/function/g_zero.h
drivers/usb/gadget/legacy/tcm_usb_gadget.c
drivers/usb/gadget/legacy/zero.c
drivers/usb/host/ehci-atmel.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/isp1760/isp1760-core.c
drivers/usb/isp1760/isp1760-udc.c
drivers/usb/musb/Kconfig
drivers/usb/phy/phy-am335x-control.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/keyspan_pda.c
drivers/usb/storage/unusual_uas.h
drivers/vhost/scsi.c
drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_mmio.c
drivers/watchdog/imgpdc_wdt.c
drivers/watchdog/mtk_wdt.c
drivers/xen/Kconfig
drivers/xen/balloon.c
drivers/xen/xen-scsiback.c
fs/affs/file.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/qgroup.c
fs/btrfs/tests/inode-tests.c
fs/btrfs/transaction.c
fs/cifs/cifsencrypt.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/fs-writeback.c
fs/fuse/dev.c
fs/hfsplus/brec.c
fs/kernfs/file.c
fs/locks.c
fs/nfsd/blocklayout.c
fs/nfsd/blocklayoutxdr.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfscache.c
fs/overlayfs/super.c
fs/proc/task_mmu.c
include/drm/drmP.h
include/drm/drm_atomic_helper.h
include/drm/drm_crtc.h
include/drm/drm_panel.h
include/kvm/arm_vgic.h
include/linux/device-mapper.h
include/linux/fs.h
include/linux/host1x.h
include/linux/irqchip/arm-gic-v3.h
include/linux/lcm.h
include/linux/libata.h
include/linux/mfd/palmas.h
include/linux/module.h
include/linux/netdevice.h
include/linux/of_graph.h
include/linux/pinctrl/consumer.h
include/linux/regulator/driver.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/sunrpc/debug.h
include/linux/usb/usbnet.h
include/linux/writeback.h
include/net/dst.h
include/net/ip.h
include/net/ip6_route.h
include/net/netfilter/nf_log.h
include/net/sock.h
include/net/vxlan.h
include/target/target_core_backend.h
include/trace/events/regmap.h
include/uapi/drm/i915_drm.h
include/uapi/drm/tegra_drm.h
include/uapi/linux/input.h
include/uapi/linux/nfsd/export.h
include/uapi/linux/virtio_blk.h
include/uapi/linux/virtio_scsi.h
include/video/samsung_fimd.h
kernel/events/core.c
kernel/livepatch/core.c
kernel/locking/lockdep.c
kernel/module.c
kernel/sched/core.c
kernel/sched/fair.c
kernel/sysctl.c
kernel/time/tick-broadcast-hrtimer.c
lib/lcm.c
lib/lz4/lz4_decompress.c
lib/nlattr.c
mm/huge_memory.c
mm/memory.c
mm/memory_hotplug.c
mm/mmap.c
mm/mprotect.c
mm/page-writeback.c
mm/page_isolation.c
mm/pagewalk.c
mm/rmap.c
mm/slub.c
net/9p/trans_virtio.c
net/bridge/br_if.c
net/caif/caif_socket.c
net/compat.c
net/core/dev.c
net/core/fib_rules.c
net/core/net_namespace.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/decnet/dn_rules.c
net/dsa/dsa.c
net/ipv4/fib_frontend.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/ip_forward.c
net/ipv4/ipmr.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_cubic.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/xfrm4_output.c
net/ipv6/fib6_rules.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp_offload.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_policy.c
net/iucv/af_iucv.c
net/l2tp/l2tp_core.c
net/mac80211/agg-rx.c
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/sta_info.h
net/mac80211/util.c
net/netfilter/nf_log.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netfilter/nfnetlink_cthelper.c
net/netfilter/nft_compat.c
net/netfilter/nft_hash.c
net/netfilter/xt_TPROXY.c
net/openvswitch/vport.c
net/rds/iw_rdma.c
net/rxrpc/ar-recvmsg.c
net/sched/act_bpf.c
net/sched/cls_u32.c
net/socket.c
net/sunrpc/clnt.c
net/sunrpc/debugfs.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/xprt.c
net/tipc/core.c
net/wireless/nl80211.c
net/xfrm/xfrm_policy.c
security/selinux/selinuxfs.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/da732x.c
sound/soc/codecs/es8328.c
sound/soc/codecs/pcm1681.c
sound/soc/codecs/rt286.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sn95031.c
sound/soc/codecs/tas5086.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/fsl/fsl_ssi.c
sound/soc/intel/sst-haswell-dsp.c
sound/soc/intel/sst-haswell-ipc.c
sound/soc/soc-core.c
tools/perf/util/annotate.c
tools/testing/selftests/Makefile
virt/kvm/arm/vgic-v2.c
virt/kvm/arm/vgic-v3.c
virt/kvm/arm/vgic.c
virt/kvm/kvm_main.c

index 7a45775..f4976cd 100644 (file)
@@ -4184,7 +4184,7 @@ int num_ioctls;</synopsis>
       <sect2>
         <title>Buffer Object Eviction</title>
        <para>
-         This section documents the interface function for evicting buffer
+         This section documents the interface functions for evicting buffer
          objects to make space available in the virtual gpu address spaces.
          Note that this is mostly orthogonal to shrinking buffer objects
          caches, which has the goal to make main memory (shared with the gpu
@@ -4192,6 +4192,17 @@ int num_ioctls;</synopsis>
        </para>
 !Idrivers/gpu/drm/i915/i915_gem_evict.c
       </sect2>
+      <sect2>
+        <title>Buffer Object Memory Shrinking</title>
+       <para>
+         This section documents the interface function for shrinking memory
+         usage of buffer object caches. Shrinking is used to make main memory
+         available.  Note that this is mostly orthogonal to evicting buffer
+         objects, which has the goal to make space in gpu virtual address
+         spaces.
+       </para>
+!Idrivers/gpu/drm/i915/i915_gem_shrinker.c
+      </sect2>
     </sect1>
 
     <sect1>
index e124847..f0b4cd7 100644 (file)
@@ -19,7 +19,9 @@ the parent DSA node. The maximum number of allowed child nodes is 4
 (DSA_MAX_SWITCHES).
 Each of these switch child nodes should have the following required properties:
 
-- reg                  : Describes the switch address on the MII bus
+- reg                  : Contains two fields. The first one describes the
+                         address on the MII bus. The second is the switch
+                         number that must be unique in cascaded configurations
 - #address-cells       : Must be 1
 - #size-cells          : Must be 0
 
diff --git a/Documentation/devicetree/bindings/panel/ampire,am800480r3tmqwa1h.txt b/Documentation/devicetree/bindings/panel/ampire,am800480r3tmqwa1h.txt
new file mode 100644 (file)
index 0000000..83e2cae
--- /dev/null
@@ -0,0 +1,7 @@
+Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "ampire,am800480r3tmqwa1h"
+
+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/auo,b101ean01.txt b/Documentation/devicetree/bindings/panel/auo,b101ean01.txt
new file mode 100644 (file)
index 0000000..3590b07
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 10.1" WSVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,b101ean01"
+
+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/innolux,at043tn24.txt b/Documentation/devicetree/bindings/panel/innolux,at043tn24.txt
new file mode 100644 (file)
index 0000000..4104226
--- /dev/null
@@ -0,0 +1,7 @@
+Innolux AT043TN24 4.3" WQVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,at043tn24"
+
+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/innolux,zj070na-01p.txt b/Documentation/devicetree/bindings/panel/innolux,zj070na-01p.txt
new file mode 100644 (file)
index 0000000..824f87f
--- /dev/null
@@ -0,0 +1,7 @@
+Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,zj070na-01p"
+
+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/ortustech,com43h4m85ulc.txt b/Documentation/devicetree/bindings/panel/ortustech,com43h4m85ulc.txt
new file mode 100644 (file)
index 0000000..de19e93
--- /dev/null
@@ -0,0 +1,7 @@
+OrtusTech COM43H4M85ULC Blanview 3.7" TFT-LCD panel
+
+Required properties:
+- compatible: should be "ortustech,com43h4m85ulc"
+
+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,ltn140at29-301.txt b/Documentation/devicetree/bindings/panel/samsung,ltn140at29-301.txt
new file mode 100644 (file)
index 0000000..e7f969d
--- /dev/null
@@ -0,0 +1,7 @@
+Samsung Electronics 14" WXGA (1366x768) TFT LCD panel
+
+Required properties:
+- compatible: should be "samsung,ltn140at29-301"
+
+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/shelly,sca07010-bfn-lnn.txt b/Documentation/devicetree/bindings/panel/shelly,sca07010-bfn-lnn.txt
new file mode 100644 (file)
index 0000000..fc1ea9e
--- /dev/null
@@ -0,0 +1,7 @@
+Shelly SCA07010-BFN-LNN 7.0" WVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "shelly,sca07010-bfn-lnn"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
index 8933211..3bf58c2 100644 (file)
@@ -1,60 +1,60 @@
-1) OF selftest platform device
+1) OF unittest platform device
 
-** selftest
+** unittest
 
 Required properties:
-- compatible: must be "selftest"
+- compatible: must be "unittest"
 
 All other properties are optional.
 
 Example:
-       selftest {
-               compatible = "selftest";
+       unittest {
+               compatible = "unittest";
                status = "okay";
        };
 
-2) OF selftest i2c adapter platform device
+2) OF unittest i2c adapter platform device
 
 ** platform device unittest adapter
 
 Required properties:
-- compatible: must be selftest-i2c-bus
+- compatible: must be unittest-i2c-bus
 
-Children nodes contain selftest i2c devices.
+Children nodes contain unittest i2c devices.
 
 Example:
-       selftest-i2c-bus {
-               compatible = "selftest-i2c-bus";
+       unittest-i2c-bus {
+               compatible = "unittest-i2c-bus";
                status = "okay";
        };
 
-3) OF selftest i2c device
+3) OF unittest i2c device
 
-** I2C selftest device
+** I2C unittest device
 
 Required properties:
-- compatible: must be selftest-i2c-dev
+- compatible: must be unittest-i2c-dev
 
 All other properties are optional
 
 Example:
-       selftest-i2c-dev {
-               compatible = "selftest-i2c-dev";
+       unittest-i2c-dev {
+               compatible = "unittest-i2c-dev";
                status = "okay";
        };
 
-4) OF selftest i2c mux device
+4) OF unittest i2c mux device
 
-** I2C selftest mux
+** I2C unittest mux
 
 Required properties:
-- compatible: must be selftest-i2c-mux
+- compatible: must be unittest-i2c-mux
 
-Children nodes contain selftest i2c bus nodes per channel.
+Children nodes contain unittest i2c bus nodes per channel.
 
 Example:
-       selftest-i2c-mux {
-               compatible = "selftest-i2c-mux";
+       unittest-i2c-mux {
+               compatible = "unittest-i2c-mux";
                status = "okay";
                #address-cells = <1>;
                #size-cells = <0>;
@@ -64,7 +64,7 @@ Example:
                        #size-cells = <0>;
                        i2c-dev {
                                reg = <8>;
-                               compatible = "selftest-i2c-dev";
+                               compatible = "unittest-i2c-dev";
                                status = "okay";
                        };
                };
index fae26d0..772b24f 100644 (file)
@@ -17,6 +17,7 @@ altr  Altera Corp.
 amcc   Applied Micro Circuits Corporation (APM, formally AMCC)
 amd    Advanced Micro Devices (AMD), Inc.
 amlogic        Amlogic, Inc.
+ampire Ampire Co., Ltd.
 ams    AMS AG
 amstaos        AMS-Taos Inc.
 apm    Applied Micro Circuits Corporation (APM)
@@ -132,6 +133,7 @@ nvidia      NVIDIA
 nxp    NXP Semiconductors
 onnn   ON Semiconductor Corp.
 opencores      OpenCores.org
+ortustech      Ortus Technology Co., Ltd.
 ovti   OmniVision Technologies
 panasonic      Panasonic Corporation
 parade Parade Technologies Inc.
similarity index 90%
rename from Documentation/devicetree/of_selftest.txt
rename to Documentation/devicetree/of_unittest.txt
index 57a808b..3e4e7d4 100644 (file)
@@ -1,11 +1,11 @@
-Open Firmware Device Tree Selftest
+Open Firmware Device Tree Unittest
 ----------------------------------
 
 Author: Gaurav Minocha <gaurav.minocha.os@gmail.com>
 
 1. Introduction
 
-This document explains how the test data required for executing OF selftest
+This document explains how the test data required for executing OF unittest
 is attached to the live tree dynamically, independent of the machine's
 architecture.
 
@@ -22,31 +22,31 @@ most of the device drivers in various use cases.
 
 2. Test-data
 
-The Device Tree Source file (drivers/of/testcase-data/testcases.dts) contains
+The Device Tree Source file (drivers/of/unittest-data/testcases.dts) contains
 the test data required for executing the unit tests automated in
-drivers/of/selftests.c. Currently, following Device Tree Source Include files
-(.dtsi) are included in testcase.dts:
+drivers/of/unittest.c. Currently, following Device Tree Source Include files
+(.dtsi) are included in testcases.dts:
 
-drivers/of/testcase-data/tests-interrupts.dtsi
-drivers/of/testcase-data/tests-platform.dtsi
-drivers/of/testcase-data/tests-phandle.dtsi
-drivers/of/testcase-data/tests-match.dtsi
+drivers/of/unittest-data/tests-interrupts.dtsi
+drivers/of/unittest-data/tests-platform.dtsi
+drivers/of/unittest-data/tests-phandle.dtsi
+drivers/of/unittest-data/tests-match.dtsi
 
 When the kernel is build with OF_SELFTEST enabled, then the following make rule
 
 $(obj)/%.dtb: $(src)/%.dts FORCE
        $(call if_changed_dep, dtc)
 
-is used to compile the DT source file (testcase.dts) into a binary blob
-(testcase.dtb), also referred as flattened DT.
+is used to compile the DT source file (testcases.dts) into a binary blob
+(testcases.dtb), also referred as flattened DT.
 
 After that, using the following rule the binary blob above is wrapped as an
-assembly file (testcase.dtb.S).
+assembly file (testcases.dtb.S).
 
 $(obj)/%.dtb.S: $(obj)/%.dtb
        $(call cmd, dt_S_dtb)
 
-The assembly file is compiled into an object file (testcase.dtb.o), and is
+The assembly file is compiled into an object file (testcases.dtb.o), and is
 linked into the kernel image.
 
 
@@ -98,7 +98,7 @@ child11 -> sibling12 -> sibling13 -> sibling14 -> null
 Figure 1: Generic structure of un-flattened device tree
 
 
-Before executing OF selftest, it is required to attach the test data to
+Before executing OF unittest, it is required to attach the test data to
 machine's device tree (if present). So, when selftest_data_add() is called,
 at first it reads the flattened device tree data linked into the kernel image
 via the following kernel symbols:
index a63e5e0..92ae734 100644 (file)
@@ -114,6 +114,9 @@ ALPS Absolute Mode - Protocol Version 2
  byte 4:  0   y6   y5   y4   y3   y2   y1   y0
  byte 5:  0   z6   z5   z4   z3   z2   z1   z0
 
+Protocol Version 2 DualPoint devices send standard PS/2 mouse packets for
+the DualPoint Stick.
+
 Dualpoint device -- interleaved packet format
 ---------------------------------------------
 
@@ -127,6 +130,11 @@ Dualpoint device -- interleaved packet format
  byte 7:    0   y6   y5   y4   y3   y2   y1   y0
  byte 8:    0   z6   z5   z4   z3   z2   z1   z0
 
+Devices which use the interleaving format normally send standard PS/2 mouse
+packets for the DualPoint Stick + ALPS Absolute Mode packets for the
+touchpad, switching to the interleaved packet format when both the stick and
+the touchpad are used at the same time.
+
 ALPS Absolute Mode - Protocol Version 3
 ---------------------------------------
 
index c587a96..9670561 100644 (file)
@@ -294,6 +294,12 @@ accordingly. This property does not affect kernel behavior.
 The kernel does not provide button emulation for such devices but treats
 them as any other INPUT_PROP_BUTTONPAD device.
 
+INPUT_PROP_ACCELEROMETER
+-------------------------
+Directional axes on this device (absolute and/or relative x, y, z) represent
+accelerometer data. All other axes retain their meaning. A device must not mix
+regular directional axes and accelerometer axes on the same event node.
+
 Guidelines:
 ==========
 The guidelines below ensure proper single-touch and multi-finger functionality.
index 7b4f59c..b85d000 100644 (file)
@@ -312,9 +312,12 @@ ABS_MT_TOOL_TYPE
 
 The type of approaching tool. A lot of kernel drivers cannot distinguish
 between different tool types, such as a finger or a pen. In such cases, the
-event should be omitted. The protocol currently supports MT_TOOL_FINGER and
-MT_TOOL_PEN [2]. For type B devices, this event is handled by input core;
-drivers should instead use input_mt_report_slot_state().
+event should be omitted. The protocol currently supports MT_TOOL_FINGER,
+MT_TOOL_PEN, and MT_TOOL_PALM [2]. For type B devices, this event is handled
+by input core; drivers should instead use input_mt_report_slot_state().
+A contact's ABS_MT_TOOL_TYPE may change over time while still touching the
+device, because the firmware may not be able to determine which tool is being
+used when it first appears.
 
 ABS_MT_BLOB_ID
 
index 7477888..6520042 100644 (file)
@@ -637,8 +637,7 @@ F:      drivers/gpu/drm/radeon/radeon_kfd.h
 F:      include/uapi/linux/kfd_ioctl.h
 
 AMD MICROCODE UPDATE SUPPORT
-M:     Andreas Herrmann <herrmann.der.user@googlemail.com>
-L:     amd64-microcode@amd64.org
+M:     Borislav Petkov <bp@alien8.de>
 S:     Maintained
 F:     arch/x86/kernel/cpu/microcode/amd*
 
@@ -1186,7 +1185,7 @@ M:        Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-mvebu/
-F:     drivers/rtc/armada38x-rtc
+F:     drivers/rtc/rtc-armada38x.c
 
 ARM/Marvell Berlin SoC support
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
@@ -1362,6 +1361,7 @@ F:        drivers/i2c/busses/i2c-rk3x.c
 F:     drivers/*/*rockchip*
 F:     drivers/*/*/*rockchip*
 F:     sound/soc/rockchip/
+N:     rockchip
 
 ARM/SAMSUNG EXYNOS ARM ARCHITECTURES
 M:     Kukjin Kim <kgene@kernel.org>
@@ -1675,8 +1675,8 @@ F:        drivers/misc/eeprom/at24.c
 F:     include/linux/platform_data/at24.h
 
 ATA OVER ETHERNET (AOE) DRIVER
-M:     "Ed L. Cashin" <ecashin@coraid.com>
-W:     http://support.coraid.com/support/linux
+M:     "Ed L. Cashin" <ed.cashin@acm.org>
+W:     http://www.openaoe.org/
 S:     Supported
 F:     Documentation/aoe/
 F:     drivers/block/aoe/
@@ -1741,7 +1741,7 @@ S:        Maintained
 F:     drivers/net/ethernet/atheros/
 
 ATM
-M:     Chas Williams <chas@cmf.nrl.navy.mil>
+M:     Chas Williams <3chas3@gmail.com>
 L:     linux-atm-general@lists.sourceforge.net (moderated for non-subscribers)
 L:     netdev@vger.kernel.org
 W:     http://linux-atm.sourceforge.net
@@ -3252,6 +3252,13 @@ S:       Maintained
 F:     Documentation/hwmon/dme1737
 F:     drivers/hwmon/dme1737.c
 
+DMI/SMBIOS SUPPORT
+M:     Jean Delvare <jdelvare@suse.de>
+S:     Maintained
+F:     drivers/firmware/dmi-id.c
+F:     drivers/firmware/dmi_scan.c
+F:     include/linux/dmi.h
+
 DOCKING STATION DRIVER
 M:     Shaohua Li <shaohua.li@intel.com>
 L:     linux-acpi@vger.kernel.org
@@ -5086,7 +5093,7 @@ S:        Supported
 F:     drivers/platform/x86/intel_menlow.c
 
 INTEL IA32 MICROCODE UPDATE SUPPORT
-M:     Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+M:     Borislav Petkov <bp@alien8.de>
 S:     Maintained
 F:     arch/x86/kernel/cpu/microcode/core*
 F:     arch/x86/kernel/cpu/microcode/intel*
@@ -5127,22 +5134,21 @@ M:      Deepak Saxena <dsaxena@plexity.net>
 S:     Maintained
 F:     drivers/char/hw_random/ixp4xx-rng.c
 
-INTEL ETHERNET DRIVERS (e100/e1000/e1000e/fm10k/igb/igbvf/ixgb/ixgbe/ixgbevf/i40e/i40evf)
+INTEL ETHERNET DRIVERS
 M:     Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-M:     Jesse Brandeburg <jesse.brandeburg@intel.com>
-M:     Bruce Allan <bruce.w.allan@intel.com>
-M:     Carolyn Wyborny <carolyn.wyborny@intel.com>
-M:     Don Skidmore <donald.c.skidmore@intel.com>
-M:     Greg Rose <gregory.v.rose@intel.com>
-M:     Matthew Vick <matthew.vick@intel.com>
-M:     John Ronciak <john.ronciak@intel.com>
-M:     Mitch Williams <mitch.a.williams@intel.com>
-M:     Linux NICS <linux.nics@intel.com>
-L:     e1000-devel@lists.sourceforge.net
+R:     Jesse Brandeburg <jesse.brandeburg@intel.com>
+R:     Shannon Nelson <shannon.nelson@intel.com>
+R:     Carolyn Wyborny <carolyn.wyborny@intel.com>
+R:     Don Skidmore <donald.c.skidmore@intel.com>
+R:     Matthew Vick <matthew.vick@intel.com>
+R:     John Ronciak <john.ronciak@intel.com>
+R:     Mitch Williams <mitch.a.williams@intel.com>
+L:     intel-wired-lan@lists.osuosl.org
 W:     http://www.intel.com/support/feedback.htm
 W:     http://e1000.sourceforge.net/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next.git
+Q:     http://patchwork.ozlabs.org/project/intel-wired-lan/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-queue.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git
 S:     Supported
 F:     Documentation/networking/e100.txt
 F:     Documentation/networking/e1000.txt
@@ -7186,6 +7192,15 @@ F:       Documentation/devicetree/
 F:     arch/*/boot/dts/
 F:     include/dt-bindings/
 
+OPEN FIRMWARE AND DEVICE TREE OVERLAYS
+M:     Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+L:     devicetree@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/dynamic-resolution-notes.txt
+F:     Documentation/devicetree/overlay-notes.txt
+F:     drivers/of/overlay.c
+F:     drivers/of/resolver.c
+
 OPENRISC ARCHITECTURE
 M:     Jonas Bonn <jonas@southpole.se>
 W:     http://openrisc.net
@@ -10206,6 +10221,13 @@ S:     Maintained
 F:     Documentation/usb/ohci.txt
 F:     drivers/usb/host/ohci*
 
+USB OTG FSM (Finite State Machine)
+M:     Peter Chen <Peter.Chen@freescale.com>
+T:     git git://github.com/hzpeterchen/linux-usb.git
+L:     linux-usb@vger.kernel.org
+S:     Maintained
+F:     drivers/usb/common/usb-otg-fsm.c
+
 USB OVER IP DRIVER
 M:     Valentina Manea <valentina.manea.m@gmail.com>
 M:     Shuah Khan <shuah.kh@samsung.com>
index e734965..54430f9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 0
 SUBLEVEL = 0
-EXTRAVERSION = -rc4
+EXTRAVERSION = -rc7
 NAME = Hurr durr I'ma sheep
 
 # *DOCUMENTATION*
index 114234e..edda76f 100644 (file)
@@ -67,7 +67,7 @@ stash_usr_regs(struct rt_sigframe __user *sf, struct pt_regs *regs,
               sigset_t *set)
 {
        int err;
-       err = __copy_to_user(&(sf->uc.uc_mcontext.regs), regs,
+       err = __copy_to_user(&(sf->uc.uc_mcontext.regs.scratch), regs,
                             sizeof(sf->uc.uc_mcontext.regs.scratch));
        err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(sigset_t));
 
@@ -83,7 +83,7 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf)
        if (!err)
                set_current_blocked(&set);
 
-       err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs),
+       err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs.scratch),
                                sizeof(sf->uc.uc_mcontext.regs.scratch));
 
        return err;
@@ -131,6 +131,15 @@ SYSCALL_DEFINE0(rt_sigreturn)
        /* Don't restart from sigreturn */
        syscall_wont_restart(regs);
 
+       /*
+        * Ensure that sigreturn always returns to user mode (in case the
+        * regs saved on user stack got fudged between save and sigreturn)
+        * Otherwise it is easy to panic the kernel with a custom
+        * signal handler and/or restorer which clobberes the status32/ret
+        * to return to a bogus location in kernel mode.
+        */
+       regs->status32 |= STATUS_U_MASK;
+
        return regs->r0;
 
 badframe:
@@ -229,8 +238,11 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
 
        /*
         * handler returns using sigreturn stub provided already by userpsace
+        * If not, nuke the process right away
         */
-       BUG_ON(!(ksig->ka.sa.sa_flags & SA_RESTORER));
+       if(!(ksig->ka.sa.sa_flags & SA_RESTORER))
+               return 1;
+
        regs->blink = (unsigned long)ksig->ka.sa.sa_restorer;
 
        /* User Stack for signal handler will be above the frame just carved */
@@ -296,12 +308,12 @@ static void
 handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 {
        sigset_t *oldset = sigmask_to_save();
-       int ret;
+       int failed;
 
        /* Set up the stack frame */
-       ret = setup_rt_frame(ksig, oldset, regs);
+       failed = setup_rt_frame(ksig, oldset, regs);
 
-       signal_setup_done(ret, ksig, 0);
+       signal_setup_done(failed, ksig, 0);
 }
 
 void do_signal(struct pt_regs *regs)
index 9f1f09a..cf4c0c9 100644 (file)
@@ -619,6 +619,7 @@ config ARCH_PXA
        select GENERIC_CLOCKEVENTS
        select GPIO_PXA
        select HAVE_IDE
+       select IRQ_DOMAIN
        select MULTI_IRQ_HANDLER
        select PLAT_PXA
        select SPARSE_IRQ
index d3a29c1..afe678f 100644 (file)
                >;
        };
 
+       mmc_pins: pinmux_mmc_pins {
+               pinctrl-single,pins = <
+                       DM816X_IOPAD(0x0a70, MUX_MODE0)                 /* SD_POW */
+                       DM816X_IOPAD(0x0a74, MUX_MODE0)                 /* SD_CLK */
+                       DM816X_IOPAD(0x0a78, MUX_MODE0)                 /* SD_CMD */
+                       DM816X_IOPAD(0x0a7C, MUX_MODE0)                 /* SD_DAT0 */
+                       DM816X_IOPAD(0x0a80, MUX_MODE0)                 /* SD_DAT1 */
+                       DM816X_IOPAD(0x0a84, MUX_MODE0)                 /* SD_DAT2 */
+                       DM816X_IOPAD(0x0a88, MUX_MODE0)                 /* SD_DAT2 */
+                       DM816X_IOPAD(0x0a8c, MUX_MODE2)                 /* GP1[7] */
+                       DM816X_IOPAD(0x0a90, MUX_MODE2)                 /* GP1[8] */
+               >;
+       };
+
        usb0_pins: pinmux_usb0_pins {
                pinctrl-single,pins = <
                        DM816X_IOPAD(0x0d00, MUX_MODE0)                 /* USB0_DRVVBUS */
 };
 
 &mmc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc_pins>;
        vmmc-supply = <&vmmcsd_fixed>;
+       bus-width = <4>;
+       cd-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
 };
 
 /* At least dm8168-evm rev c won't support multipoint, later may */
index 3c97b5f..f35715b 100644 (file)
                };
 
                gpio1: gpio@48032000 {
-                       compatible = "ti,omap3-gpio";
+                       compatible = "ti,omap4-gpio";
                        ti,hwmods = "gpio1";
+                       ti,gpio-always-on;
                        reg = <0x48032000 0x1000>;
-                       interrupts = <97>;
+                       interrupts = <96>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
 
                gpio2: gpio@4804c000 {
-                       compatible = "ti,omap3-gpio";
+                       compatible = "ti,omap4-gpio";
                        ti,hwmods = "gpio2";
+                       ti,gpio-always-on;
                        reg = <0x4804c000 0x1000>;
-                       interrupts = <99>;
+                       interrupts = <98>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
 
                gpmc: gpmc@50000000 {
index 127608d..c4659a9 100644 (file)
                                              "wkupclk", "refclk",
                                              "div-clk", "phy-div";
                                #phy-cells = <0>;
-                               ti,hwmods = "pcie1-phy";
                        };
 
                        pcie2_phy: pciephy@4a095000 {
                                              "wkupclk", "refclk",
                                              "div-clk", "phy-div";
                                #phy-cells = <0>;
-                               ti,hwmods = "pcie2-phy";
                                status = "disabled";
                        };
                };
index f4f78c4..3fdc84f 100644 (file)
@@ -92,6 +92,8 @@
                        ti,hwmods = "aes";
                        reg = <0x480c5000 0x50>;
                        interrupts = <0>;
+                       dmas = <&sdma 65 &sdma 66>;
+                       dma-names = "tx", "rx";
                };
 
                prm: prm@48306000 {
                        ti,hwmods = "sham";
                        reg = <0x480c3000 0x64>;
                        interrupts = <49>;
+                       dmas = <&sdma 69>;
+                       dma-names = "rx";
                };
 
                smartreflex_core: smartreflex@480cb000 {
index d771f68..eccc78d 100644 (file)
                        "mac_clk_rx", "mac_clk_tx",
                        "clk_mac_ref", "clk_mac_refout",
                        "aclk_mac", "pclk_mac";
+               status = "disabled";
        };
 
        usb_host0_ehci: usb@ff500000 {
index 9d87609..d9176e6 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0xfff01000 0x1000>;
-                       interrupts = <0 156 4>;
+                       interrupts = <0 155 4>;
                        num-cs = <4>;
                        clocks = <&spi_m_clk>;
                        status = "disabled";
index ab7891c..75742f8 100644 (file)
        model = "Olimex A10-OLinuXino-LIME";
        compatible = "olimex,a10-olinuxino-lime", "allwinner,sun4i-a10";
 
+       cpus {
+               cpu0: cpu@0 {
+                       /*
+                        * The A10-Lime is known to be unstable
+                        * when running at 1008 MHz
+                        */
+                       operating-points = <
+                               /* kHz    uV */
+                               912000  1350000
+                               864000  1300000
+                               624000  1250000
+                               >;
+                       cooling-max-level = <2>;
+               };
+       };
+
        soc@01c00000 {
                emac: ethernet@01c0b000 {
                        pinctrl-names = "default";
index 5c29258..eebb785 100644 (file)
@@ -75,7 +75,6 @@
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1056000 1500000
                                1008000 1400000
                                912000  1350000
                                864000  1300000
@@ -83,7 +82,7 @@
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <4>;
+                       cooling-max-level = <3>;
                };
        };
 
index f8818f1..883cb48 100644 (file)
@@ -47,7 +47,6 @@
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1104000 1500000
                                1008000 1400000
                                912000  1350000
                                864000  1300000
@@ -57,7 +56,7 @@
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <6>;
+                       cooling-max-level = <5>;
                };
        };
 
index 3a8530b..fdd1817 100644 (file)
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1008000 1450000
                                960000  1400000
                                912000  1400000
                                864000  1300000
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <7>;
+                       cooling-max-level = <6>;
                };
 
                cpu@1 {
index 71e5fc7..1d1800f 100644 (file)
 # define VFP_ABI_FRAME 0
 # define BSAES_ASM_EXTENDED_KEY
 # define XTS_CHAIN_TWEAK
-# define __ARM_ARCH__  7
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_MAX_ARCH__ 7
 #endif
 
 #ifdef __thumb__
 # define adrl adr
 #endif
 
-#if __ARM_ARCH__>=7
+#if __ARM_MAX_ARCH__>=7
+.arch  armv7-a
+.fpu   neon
+
 .text
 .syntax        unified         @ ARMv7-capable assembler is expected to handle this
 #ifdef __thumb2__
@@ -74,8 +78,6 @@
 .code   32
 #endif
 
-.fpu   neon
-
 .type  _bsaes_decrypt8,%function
 .align 4
 _bsaes_decrypt8:
@@ -2095,9 +2097,11 @@ bsaes_xts_decrypt:
        vld1.8  {q8}, [r0]                      @ initial tweak
        adr     r2, .Lxts_magic
 
+#ifndef        XTS_CHAIN_TWEAK
        tst     r9, #0xf                        @ if not multiple of 16
        it      ne                              @ Thumb2 thing, sanity check in ARM
        subne   r9, #0x10                       @ subtract another 16 bytes
+#endif
        subs    r9, #0x80
 
        blo     .Lxts_dec_short
index be068db..a4d3856 100644 (file)
@@ -701,14 +701,18 @@ $code.=<<___;
 # define VFP_ABI_FRAME 0
 # define BSAES_ASM_EXTENDED_KEY
 # define XTS_CHAIN_TWEAK
-# define __ARM_ARCH__  7
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_MAX_ARCH__ 7
 #endif
 
 #ifdef __thumb__
 # define adrl adr
 #endif
 
-#if __ARM_ARCH__>=7
+#if __ARM_MAX_ARCH__>=7
+.arch  armv7-a
+.fpu   neon
+
 .text
 .syntax        unified         @ ARMv7-capable assembler is expected to handle this
 #ifdef __thumb2__
@@ -717,8 +721,6 @@ $code.=<<___;
 .code   32
 #endif
 
-.fpu   neon
-
 .type  _bsaes_decrypt8,%function
 .align 4
 _bsaes_decrypt8:
@@ -2076,9 +2078,11 @@ bsaes_xts_decrypt:
        vld1.8  {@XMM[8]}, [r0]                 @ initial tweak
        adr     $magic, .Lxts_magic
 
+#ifndef        XTS_CHAIN_TWEAK
        tst     $len, #0xf                      @ if not multiple of 16
        it      ne                              @ Thumb2 thing, sanity check in ARM
        subne   $len, #0x10                     @ subtract another 16 bytes
+#endif
        subs    $len, #0x80
 
        blo     .Lxts_dec_short
index bf0fe99..4cf48c3 100644 (file)
@@ -149,29 +149,28 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
        (__boundary - 1 < (end) - 1)? __boundary: (end);                \
 })
 
+#define kvm_pgd_index(addr)                    pgd_index(addr)
+
 static inline bool kvm_page_empty(void *ptr)
 {
        struct page *ptr_page = virt_to_page(ptr);
        return page_count(ptr_page) == 1;
 }
 
-
 #define kvm_pte_table_empty(kvm, ptep) kvm_page_empty(ptep)
 #define kvm_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp)
 #define kvm_pud_table_empty(kvm, pudp) (0)
 
 #define KVM_PREALLOC_LEVEL     0
 
-static inline int kvm_prealloc_hwpgd(struct kvm *kvm, pgd_t *pgd)
+static inline void *kvm_get_hwpgd(struct kvm *kvm)
 {
-       return 0;
+       return kvm->arch.pgd;
 }
 
-static inline void kvm_free_hwpgd(struct kvm *kvm) { }
-
-static inline void *kvm_get_hwpgd(struct kvm *kvm)
+static inline unsigned int kvm_get_hwpgd_size(void)
 {
-       return kvm->arch.pgd;
+       return PTRS_PER_S2_PGD * sizeof(pgd_t);
 }
 
 struct kvm;
index e55408e..1d60beb 100644 (file)
@@ -246,12 +246,9 @@ static int __get_cpu_architecture(void)
                if (cpu_arch)
                        cpu_arch += CPU_ARCH_ARMv3;
        } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
-               unsigned int mmfr0;
-
                /* Revised CPUID format. Read the Memory Model Feature
                 * Register 0 and check for VMSAv7 or PMSAv7 */
-               asm("mrc        p15, 0, %0, c0, c1, 4"
-                   : "=r" (mmfr0));
+               unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0);
                if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
                    (mmfr0 & 0x000000f0) >= 0x00000030)
                        cpu_arch = CPU_ARCH_ARMv7;
index 3e6859b..5656d79 100644 (file)
@@ -290,7 +290,7 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
        phys_addr_t addr = start, end = start + size;
        phys_addr_t next;
 
-       pgd = pgdp + pgd_index(addr);
+       pgd = pgdp + kvm_pgd_index(addr);
        do {
                next = kvm_pgd_addr_end(addr, end);
                if (!pgd_none(*pgd))
@@ -355,7 +355,7 @@ static void stage2_flush_memslot(struct kvm *kvm,
        phys_addr_t next;
        pgd_t *pgd;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        do {
                next = kvm_pgd_addr_end(addr, end);
                stage2_flush_puds(kvm, pgd, addr, next);
@@ -632,6 +632,20 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
                                     __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE);
 }
 
+/* Free the HW pgd, one page at a time */
+static void kvm_free_hwpgd(void *hwpgd)
+{
+       free_pages_exact(hwpgd, kvm_get_hwpgd_size());
+}
+
+/* Allocate the HW PGD, making sure that each page gets its own refcount */
+static void *kvm_alloc_hwpgd(void)
+{
+       unsigned int size = kvm_get_hwpgd_size();
+
+       return alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
+}
+
 /**
  * kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
  * @kvm:       The KVM struct pointer for the VM.
@@ -645,15 +659,31 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
  */
 int kvm_alloc_stage2_pgd(struct kvm *kvm)
 {
-       int ret;
        pgd_t *pgd;
+       void *hwpgd;
 
        if (kvm->arch.pgd != NULL) {
                kvm_err("kvm_arch already initialized?\n");
                return -EINVAL;
        }
 
+       hwpgd = kvm_alloc_hwpgd();
+       if (!hwpgd)
+               return -ENOMEM;
+
+       /* When the kernel uses more levels of page tables than the
+        * guest, we allocate a fake PGD and pre-populate it to point
+        * to the next-level page table, which will be the real
+        * initial page table pointed to by the VTTBR.
+        *
+        * When KVM_PREALLOC_LEVEL==2, we allocate a single page for
+        * the PMD and the kernel will use folded pud.
+        * When KVM_PREALLOC_LEVEL==1, we allocate 2 consecutive PUD
+        * pages.
+        */
        if (KVM_PREALLOC_LEVEL > 0) {
+               int i;
+
                /*
                 * Allocate fake pgd for the page table manipulation macros to
                 * work.  This is not used by the hardware and we have no
@@ -661,30 +691,32 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
                 */
                pgd = (pgd_t *)kmalloc(PTRS_PER_S2_PGD * sizeof(pgd_t),
                                       GFP_KERNEL | __GFP_ZERO);
+
+               if (!pgd) {
+                       kvm_free_hwpgd(hwpgd);
+                       return -ENOMEM;
+               }
+
+               /* Plug the HW PGD into the fake one. */
+               for (i = 0; i < PTRS_PER_S2_PGD; i++) {
+                       if (KVM_PREALLOC_LEVEL == 1)
+                               pgd_populate(NULL, pgd + i,
+                                            (pud_t *)hwpgd + i * PTRS_PER_PUD);
+                       else if (KVM_PREALLOC_LEVEL == 2)
+                               pud_populate(NULL, pud_offset(pgd, 0) + i,
+                                            (pmd_t *)hwpgd + i * PTRS_PER_PMD);
+               }
        } else {
                /*
                 * Allocate actual first-level Stage-2 page table used by the
                 * hardware for Stage-2 page table walks.
                 */
-               pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, S2_PGD_ORDER);
+               pgd = (pgd_t *)hwpgd;
        }
 
-       if (!pgd)
-               return -ENOMEM;
-
-       ret = kvm_prealloc_hwpgd(kvm, pgd);
-       if (ret)
-               goto out_err;
-
        kvm_clean_pgd(pgd);
        kvm->arch.pgd = pgd;
        return 0;
-out_err:
-       if (KVM_PREALLOC_LEVEL > 0)
-               kfree(pgd);
-       else
-               free_pages((unsigned long)pgd, S2_PGD_ORDER);
-       return ret;
 }
 
 /**
@@ -785,11 +817,10 @@ void kvm_free_stage2_pgd(struct kvm *kvm)
                return;
 
        unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
-       kvm_free_hwpgd(kvm);
+       kvm_free_hwpgd(kvm_get_hwpgd(kvm));
        if (KVM_PREALLOC_LEVEL > 0)
                kfree(kvm->arch.pgd);
-       else
-               free_pages((unsigned long)kvm->arch.pgd, S2_PGD_ORDER);
+
        kvm->arch.pgd = NULL;
 }
 
@@ -799,7 +830,7 @@ static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache
        pgd_t *pgd;
        pud_t *pud;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        if (WARN_ON(pgd_none(*pgd))) {
                if (!cache)
                        return NULL;
@@ -1089,7 +1120,7 @@ static void stage2_wp_range(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)
        pgd_t *pgd;
        phys_addr_t next;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        do {
                /*
                 * Release kvm_mmu_lock periodically if the memory region is
index 2a2f4d5..25f1bee 100644 (file)
@@ -720,6 +720,8 @@ static const char * __init omap_get_family(void)
                return kasprintf(GFP_KERNEL, "OMAP4");
        else if (soc_is_omap54xx())
                return kasprintf(GFP_KERNEL, "OMAP5");
+       else if (soc_is_am33xx() || soc_is_am335x())
+               return kasprintf(GFP_KERNEL, "AM33xx");
        else if (soc_is_am43xx())
                return kasprintf(GFP_KERNEL, "AM43xx");
        else if (soc_is_dra7xx())
index 0eecd83..89a7c06 100644 (file)
@@ -11,6 +11,7 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
+#include <linux/bitops.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
@@ -40,7 +41,6 @@
 #define ICHP_VAL_IRQ           (1 << 31)
 #define ICHP_IRQ(i)            (((i) >> 16) & 0x7fff)
 #define IPR_VALID              (1 << 31)
-#define IRQ_BIT(n)             (((n) - PXA_IRQ(0)) & 0x1f)
 
 #define MAX_INTERNAL_IRQS      128
 
@@ -51,6 +51,7 @@
 static void __iomem *pxa_irq_base;
 static int pxa_internal_irq_nr;
 static bool cpu_has_ipr;
+static struct irq_domain *pxa_irq_domain;
 
 static inline void __iomem *irq_base(int i)
 {
@@ -66,18 +67,20 @@ static inline void __iomem *irq_base(int i)
 void pxa_mask_irq(struct irq_data *d)
 {
        void __iomem *base = irq_data_get_irq_chip_data(d);
+       irq_hw_number_t irq = irqd_to_hwirq(d);
        uint32_t icmr = __raw_readl(base + ICMR);
 
-       icmr &= ~(1 << IRQ_BIT(d->irq));
+       icmr &= ~BIT(irq & 0x1f);
        __raw_writel(icmr, base + ICMR);
 }
 
 void pxa_unmask_irq(struct irq_data *d)
 {
        void __iomem *base = irq_data_get_irq_chip_data(d);
+       irq_hw_number_t irq = irqd_to_hwirq(d);
        uint32_t icmr = __raw_readl(base + ICMR);
 
-       icmr |= 1 << IRQ_BIT(d->irq);
+       icmr |= BIT(irq & 0x1f);
        __raw_writel(icmr, base + ICMR);
 }
 
@@ -118,40 +121,63 @@ asmlinkage void __exception_irq_entry ichp_handle_irq(struct pt_regs *regs)
        } while (1);
 }
 
-void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
+static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
+                      irq_hw_number_t hw)
 {
-       int irq, i, n;
+       void __iomem *base = irq_base(hw / 32);
 
-       BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
+       /* initialize interrupt priority */
+       if (cpu_has_ipr)
+               __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
+
+       irq_set_chip_and_handler(virq, &pxa_internal_irq_chip,
+                                handle_level_irq);
+       irq_set_chip_data(virq, base);
+       set_irq_flags(virq, IRQF_VALID);
+
+       return 0;
+}
+
+static struct irq_domain_ops pxa_irq_ops = {
+       .map    = pxa_irq_map,
+       .xlate  = irq_domain_xlate_onecell,
+};
+
+static __init void
+pxa_init_irq_common(struct device_node *node, int irq_nr,
+                   int (*fn)(struct irq_data *, unsigned int))
+{
+       int n;
 
        pxa_internal_irq_nr = irq_nr;
-       cpu_has_ipr = !cpu_is_pxa25x();
-       pxa_irq_base = io_p2v(0x40d00000);
+       pxa_irq_domain = irq_domain_add_legacy(node, irq_nr,
+                                              PXA_IRQ(0), 0,
+                                              &pxa_irq_ops, NULL);
+       if (!pxa_irq_domain)
+               panic("Unable to add PXA IRQ domain\n");
+       irq_set_default_host(pxa_irq_domain);
 
        for (n = 0; n < irq_nr; n += 32) {
                void __iomem *base = irq_base(n >> 5);
 
                __raw_writel(0, base + ICMR);   /* disable all IRQs */
                __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
-               for (i = n; (i < (n + 32)) && (i < irq_nr); i++) {
-                       /* initialize interrupt priority */
-                       if (cpu_has_ipr)
-                               __raw_writel(i | IPR_VALID, pxa_irq_base + IPR(i));
-
-                       irq = PXA_IRQ(i);
-                       irq_set_chip_and_handler(irq, &pxa_internal_irq_chip,
-                                                handle_level_irq);
-                       irq_set_chip_data(irq, base);
-                       set_irq_flags(irq, IRQF_VALID);
-               }
        }
-
        /* only unmasked interrupts kick us out of idle */
        __raw_writel(1, irq_base(0) + ICCR);
 
        pxa_internal_irq_chip.irq_set_wake = fn;
 }
 
+void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
+{
+       BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
+
+       pxa_irq_base = io_p2v(0x40d00000);
+       cpu_has_ipr = !cpu_is_pxa25x();
+       pxa_init_irq_common(NULL, irq_nr, fn);
+}
+
 #ifdef CONFIG_PM
 static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
 static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
@@ -203,30 +229,6 @@ struct syscore_ops pxa_irq_syscore_ops = {
 };
 
 #ifdef CONFIG_OF
-static struct irq_domain *pxa_irq_domain;
-
-static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
-                      irq_hw_number_t hw)
-{
-       void __iomem *base = irq_base(hw / 32);
-
-       /* initialize interrupt priority */
-       if (cpu_has_ipr)
-               __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
-
-       irq_set_chip_and_handler(hw, &pxa_internal_irq_chip,
-                                handle_level_irq);
-       irq_set_chip_data(hw, base);
-       set_irq_flags(hw, IRQF_VALID);
-
-       return 0;
-}
-
-static struct irq_domain_ops pxa_irq_ops = {
-       .map    = pxa_irq_map,
-       .xlate  = irq_domain_xlate_onecell,
-};
-
 static const struct of_device_id intc_ids[] __initconst = {
        { .compatible = "marvell,pxa-intc", },
        {}
@@ -236,7 +238,7 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
 {
        struct device_node *node;
        struct resource res;
-       int n, ret;
+       int ret;
 
        node = of_find_matching_node(NULL, intc_ids);
        if (!node) {
@@ -267,23 +269,6 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
                return;
        }
 
-       pxa_irq_domain = irq_domain_add_legacy(node, pxa_internal_irq_nr, 0, 0,
-                                              &pxa_irq_ops, NULL);
-       if (!pxa_irq_domain)
-               panic("Unable to add PXA IRQ domain\n");
-
-       irq_set_default_host(pxa_irq_domain);
-
-       for (n = 0; n < pxa_internal_irq_nr; n += 32) {
-               void __iomem *base = irq_base(n >> 5);
-
-               __raw_writel(0, base + ICMR);   /* disable all IRQs */
-               __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
-       }
-
-       /* only unmasked interrupts kick us out of idle */
-       __raw_writel(1, irq_base(0) + ICCR);
-
-       pxa_internal_irq_chip.irq_set_wake = fn;
+       pxa_init_irq_common(node, pxa_internal_irq_nr, fn);
 }
 #endif /* CONFIG_OF */
index 205f9bf..ac2ae5c 100644 (file)
@@ -412,7 +412,7 @@ static struct fixed_voltage_config can_regulator_pdata = {
 };
 
 static struct platform_device can_regulator_device = {
-       .name   = "reg-fixed-volage",
+       .name   = "reg-fixed-voltage",
        .id     = 0,
        .dev    = {
                .platform_data  = &can_regulator_pdata,
index a77604f..81502b9 100644 (file)
@@ -1,10 +1,12 @@
 menuconfig ARCH_SUNXI
        bool "Allwinner SoCs" if ARCH_MULTI_V7
        select ARCH_REQUIRE_GPIOLIB
+       select ARCH_HAS_RESET_CONTROLLER
        select CLKSRC_MMIO
        select GENERIC_IRQ_CHIP
        select PINCTRL
        select SUN4I_TIMER
+       select RESET_CONTROLLER
 
 if ARCH_SUNXI
 
@@ -20,10 +22,8 @@ config MACH_SUN5I
 config MACH_SUN6I
        bool "Allwinner A31 (sun6i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
        select MFD_SUN6I_PRCM
-       select RESET_CONTROLLER
        select SUN5I_HSTIMER
 
 config MACH_SUN7I
@@ -37,16 +37,12 @@ config MACH_SUN7I
 config MACH_SUN8I
        bool "Allwinner A23 (sun8i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
        select MFD_SUN6I_PRCM
-       select RESET_CONTROLLER
 
 config MACH_SUN9I
        bool "Allwinner (sun9i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
-       select RESET_CONTROLLER
 
 endif
index c6c7696..8f15f70 100644 (file)
@@ -1131,23 +1131,22 @@ static void __init l2c310_of_parse(const struct device_node *np,
        }
 
        ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K);
-       if (ret)
-               return;
-
-       switch (assoc) {
-       case 16:
-               *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               *aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16;
-               *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               break;
-       case 8:
-               *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               break;
-       default:
-               pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
-                      assoc);
-               break;
+       if (!ret) {
+               switch (assoc) {
+               case 16:
+                       *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       *aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16;
+                       *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       break;
+               case 8:
+                       *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       break;
+               default:
+                       pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
+                              assoc);
+                       break;
+               }
        }
 
        prefetch = l2x0_saved_regs.prefetch_ctrl;
index 170a116..c274476 100644 (file)
@@ -171,7 +171,7 @@ static int __dma_supported(struct device *dev, u64 mask, bool warn)
         */
        if (sizeof(mask) != sizeof(dma_addr_t) &&
            mask > (dma_addr_t)~0 &&
-           dma_to_pfn(dev, ~0) < max_pfn) {
+           dma_to_pfn(dev, ~0) < max_pfn - 1) {
                if (warn) {
                        dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n",
                                 mask);
index a982dc3..6333d9c 100644 (file)
@@ -552,6 +552,7 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 
        pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n",
                inf->name, fsr, addr);
+       show_pte(current->mm, addr);
 
        info.si_signo = inf->sig;
        info.si_errno = 0;
index 004e35c..cf30daf 100644 (file)
@@ -49,7 +49,10 @@ static int change_memory_common(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
-       if (!is_module_address(start) || !is_module_address(end - 1))
+       if (start < MODULES_VADDR || start >= MODULES_END)
+               return -EINVAL;
+
+       if (end < MODULES_VADDR || start >= MODULES_END)
                return -EINVAL;
 
        data.set_mask = set_mask;
index db10169..8ca94d3 100644 (file)
@@ -799,6 +799,7 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        const struct of_device_id *match;
        const struct dmtimer_platform_data *pdata;
+       int ret;
 
        match = of_match_device(of_match_ptr(omap_timer_match), dev);
        pdata = match ? match->data : dev->platform_data;
@@ -860,7 +861,12 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        }
 
        if (!timer->reserved) {
-               pm_runtime_get_sync(dev);
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0) {
+                       dev_err(dev, "%s: pm_runtime_get_sync failed!\n",
+                               __func__);
+                       goto err_get_sync;
+               }
                __omap_dm_timer_init_regs(timer);
                pm_runtime_put(dev);
        }
@@ -873,6 +879,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        dev_dbg(dev, "Device Probed.\n");
 
        return 0;
+
+err_get_sync:
+       pm_runtime_put_noidle(dev);
+       pm_runtime_disable(dev);
+       return ret;
 }
 
 /**
@@ -899,6 +910,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev)
                }
        spin_unlock_irqrestore(&dm_timer_lock, flags);
 
+       pm_runtime_disable(&pdev->dev);
+
        return ret;
 }
 
index ea2b566..c9b89ef 100644 (file)
@@ -8,7 +8,7 @@
  */
 
        /* SoC fixed clocks */
-       soc_uartclk: refclk72738khz {
+       soc_uartclk: refclk7273800hz {
                compatible = "fixed-clock";
                #clock-cells = <0>;
                clock-frequency = <7273800>;
index cb95930..d8c25b7 100644 (file)
@@ -246,14 +246,30 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
        __ret; \
 })
 
-#define this_cpu_cmpxchg_1(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_2(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_4(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_8(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-
-#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
-       cmpxchg_double_local(raw_cpu_ptr(&(ptr1)), raw_cpu_ptr(&(ptr2)), \
-                               o1, o2, n1, n2)
+#define _protect_cmpxchg_local(pcp, o, n)                      \
+({                                                             \
+       typeof(*raw_cpu_ptr(&(pcp))) __ret;                     \
+       preempt_disable();                                      \
+       __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n);       \
+       preempt_enable();                                       \
+       __ret;                                                  \
+})
+
+#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+
+#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2)          \
+({                                                                     \
+       int __ret;                                                      \
+       preempt_disable();                                              \
+       __ret = cmpxchg_double_local(   raw_cpu_ptr(&(ptr1)),           \
+                                       raw_cpu_ptr(&(ptr2)),           \
+                                       o1, o2, n1, n2);                \
+       preempt_enable();                                               \
+       __ret;                                                          \
+})
 
 #define cmpxchg64(ptr,o,n)             cmpxchg((ptr),(o),(n))
 #define cmpxchg64_local(ptr,o,n)       cmpxchg_local((ptr),(o),(n))
index 94674eb..54bb4ba 100644 (file)
  * 40 bits wide (T0SZ = 24).  Systems with a PARange smaller than 40 bits are
  * not known to exist and will break with this configuration.
  *
+ * VTCR_EL2.PS is extracted from ID_AA64MMFR0_EL1.PARange at boot time
+ * (see hyp-init.S).
+ *
  * Note that when using 4K pages, we concatenate two first level page tables
  * together.
  *
 #ifdef CONFIG_ARM64_64K_PAGES
 /*
  * Stage2 translation configuration:
- * 40bits output (PS = 2)
  * 40bits input  (T0SZ = 24)
  * 64kB pages (TG0 = 1)
  * 2 level page tables (SL = 1)
 #else
 /*
  * Stage2 translation configuration:
- * 40bits output (PS = 2)
  * 40bits input  (T0SZ = 24)
  * 4kB pages (TG0 = 0)
  * 3 level page tables (SL = 1)
index 6458b53..bbfb600 100644 (file)
@@ -158,6 +158,8 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
 #define PTRS_PER_S2_PGD                (1 << PTRS_PER_S2_PGD_SHIFT)
 #define S2_PGD_ORDER           get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
 
+#define kvm_pgd_index(addr)    (((addr) >> PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1))
+
 /*
  * If we are concatenating first level stage-2 page tables, we would have less
  * than or equal to 16 pointers in the fake PGD, because that's what the
@@ -171,43 +173,6 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
 #define KVM_PREALLOC_LEVEL     (0)
 #endif
 
-/**
- * kvm_prealloc_hwpgd - allocate inital table for VTTBR
- * @kvm:       The KVM struct pointer for the VM.
- * @pgd:       The kernel pseudo pgd
- *
- * When the kernel uses more levels of page tables than the guest, we allocate
- * a fake PGD and pre-populate it to point to the next-level page table, which
- * will be the real initial page table pointed to by the VTTBR.
- *
- * When KVM_PREALLOC_LEVEL==2, we allocate a single page for the PMD and
- * the kernel will use folded pud.  When KVM_PREALLOC_LEVEL==1, we
- * allocate 2 consecutive PUD pages.
- */
-static inline int kvm_prealloc_hwpgd(struct kvm *kvm, pgd_t *pgd)
-{
-       unsigned int i;
-       unsigned long hwpgd;
-
-       if (KVM_PREALLOC_LEVEL == 0)
-               return 0;
-
-       hwpgd = __get_free_pages(GFP_KERNEL | __GFP_ZERO, PTRS_PER_S2_PGD_SHIFT);
-       if (!hwpgd)
-               return -ENOMEM;
-
-       for (i = 0; i < PTRS_PER_S2_PGD; i++) {
-               if (KVM_PREALLOC_LEVEL == 1)
-                       pgd_populate(NULL, pgd + i,
-                                    (pud_t *)hwpgd + i * PTRS_PER_PUD);
-               else if (KVM_PREALLOC_LEVEL == 2)
-                       pud_populate(NULL, pud_offset(pgd, 0) + i,
-                                    (pmd_t *)hwpgd + i * PTRS_PER_PMD);
-       }
-
-       return 0;
-}
-
 static inline void *kvm_get_hwpgd(struct kvm *kvm)
 {
        pgd_t *pgd = kvm->arch.pgd;
@@ -224,12 +189,11 @@ static inline void *kvm_get_hwpgd(struct kvm *kvm)
        return pmd_offset(pud, 0);
 }
 
-static inline void kvm_free_hwpgd(struct kvm *kvm)
+static inline unsigned int kvm_get_hwpgd_size(void)
 {
-       if (KVM_PREALLOC_LEVEL > 0) {
-               unsigned long hwpgd = (unsigned long)kvm_get_hwpgd(kvm);
-               free_pages(hwpgd, PTRS_PER_S2_PGD_SHIFT);
-       }
+       if (KVM_PREALLOC_LEVEL > 0)
+               return PTRS_PER_S2_PGD * PAGE_SIZE;
+       return PTRS_PER_S2_PGD * sizeof(pgd_t);
 }
 
 static inline bool kvm_page_empty(void *ptr)
index a9eee33..101a42b 100644 (file)
@@ -151,6 +151,15 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
 {
        unsigned int cpu = smp_processor_id();
 
+       /*
+        * init_mm.pgd does not contain any user mappings and it is always
+        * active for kernel addresses in TTBR1. Just set the reserved TTBR0.
+        */
+       if (next == &init_mm) {
+               cpu_set_reserved_ttbr0();
+               return;
+       }
+
        if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next)
                check_and_switch_context(next, tsk);
 }
index 09da25b..4fde8c1 100644 (file)
@@ -204,25 +204,47 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
        return ret;
 }
 
+#define _percpu_read(pcp)                                              \
+({                                                                     \
+       typeof(pcp) __retval;                                           \
+       preempt_disable();                                              \
+       __retval = (typeof(pcp))__percpu_read(raw_cpu_ptr(&(pcp)),      \
+                                             sizeof(pcp));             \
+       preempt_enable();                                               \
+       __retval;                                                       \
+})
+
+#define _percpu_write(pcp, val)                                                \
+do {                                                                   \
+       preempt_disable();                                              \
+       __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val),       \
+                               sizeof(pcp));                           \
+       preempt_enable();                                               \
+} while(0)                                                             \
+
+#define _pcp_protect(operation, pcp, val)                      \
+({                                                             \
+       typeof(pcp) __retval;                                   \
+       preempt_disable();                                      \
+       __retval = (typeof(pcp))operation(raw_cpu_ptr(&(pcp)),  \
+                                         (val), sizeof(pcp));  \
+       preempt_enable();                                       \
+       __retval;                                               \
+})
+
 #define _percpu_add(pcp, val) \
-       __percpu_add(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+       _pcp_protect(__percpu_add, pcp, val)
 
-#define _percpu_add_return(pcp, val) (typeof(pcp)) (_percpu_add(pcp, val))
+#define _percpu_add_return(pcp, val) _percpu_add(pcp, val)
 
 #define _percpu_and(pcp, val) \
-       __percpu_and(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+       _pcp_protect(__percpu_and, pcp, val)
 
 #define _percpu_or(pcp, val) \
-       __percpu_or(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
-
-#define _percpu_read(pcp) (typeof(pcp))        \
-       (__percpu_read(raw_cpu_ptr(&(pcp)), sizeof(pcp)))
-
-#define _percpu_write(pcp, val) \
-       __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp))
+       _pcp_protect(__percpu_or, pcp, val)
 
 #define _percpu_xchg(pcp, val) (typeof(pcp)) \
-       (__percpu_xchg(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp)))
+       _pcp_protect(__percpu_xchg, pcp, (unsigned long)(val))
 
 #define this_cpu_add_1(pcp, val) _percpu_add(pcp, val)
 #define this_cpu_add_2(pcp, val) _percpu_add(pcp, val)
index 9a8fd84..941c375 100644 (file)
@@ -39,7 +39,11 @@ extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
 
 #include <asm/memory.h>
 
-#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
+#define cpu_switch_mm(pgd,mm)                          \
+do {                                                   \
+       BUG_ON(pgd == swapper_pg_dir);                  \
+       cpu_do_switch_mm(virt_to_phys(pgd),mm);         \
+} while (0)
 
 #define cpu_get_pgd()                                  \
 ({                                                     \
index 2b8d701..ab21e0d 100644 (file)
@@ -337,7 +337,11 @@ core_initcall(arm64_dmi_init);
 
 static void efi_set_pgd(struct mm_struct *mm)
 {
-       cpu_switch_mm(mm->pgd, mm);
+       if (mm == &init_mm)
+               cpu_set_reserved_ttbr0();
+       else
+               cpu_switch_mm(mm->pgd, mm);
+
        flush_tlb_all();
        if (icache_is_aivivt())
                __flush_icache_all();
index 58e0c2b..ef7d112 100644 (file)
@@ -51,7 +51,7 @@ static int __init early_coherent_pool(char *p)
 }
 early_param("coherent_pool", early_coherent_pool);
 
-static void *__alloc_from_pool(size_t size, struct page **ret_page)
+static void *__alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags)
 {
        unsigned long val;
        void *ptr = NULL;
@@ -67,6 +67,8 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page)
 
                *ret_page = phys_to_page(phys);
                ptr = (void *)val;
+               if (flags & __GFP_ZERO)
+                       memset(ptr, 0, size);
        }
 
        return ptr;
@@ -101,6 +103,7 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
                flags |= GFP_DMA;
        if (IS_ENABLED(CONFIG_DMA_CMA) && (flags & __GFP_WAIT)) {
                struct page *page;
+               void *addr;
 
                size = PAGE_ALIGN(size);
                page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
@@ -109,7 +112,10 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
                        return NULL;
 
                *dma_handle = phys_to_dma(dev, page_to_phys(page));
-               return page_address(page);
+               addr = page_address(page);
+               if (flags & __GFP_ZERO)
+                       memset(addr, 0, size);
+               return addr;
        } else {
                return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
        }
@@ -146,7 +152,7 @@ static void *__dma_alloc(struct device *dev, size_t size,
 
        if (!coherent && !(flags & __GFP_WAIT)) {
                struct page *page = NULL;
-               void *addr = __alloc_from_pool(size, &page);
+               void *addr = __alloc_from_pool(size, &page, flags);
 
                if (addr)
                        *dma_handle = phys_to_dma(dev, page_to_phys(page));
index 9359e50..d5779b0 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_METAG_IO_H
 
 #include <linux/types.h>
+#include <asm/pgtable-bits.h>
 
 #define IO_SPACE_LIMIT  0
 
diff --git a/arch/metag/include/asm/pgtable-bits.h b/arch/metag/include/asm/pgtable-bits.h
new file mode 100644 (file)
index 0000000..25ba672
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Meta page table definitions.
+ */
+
+#ifndef _METAG_PGTABLE_BITS_H
+#define _METAG_PGTABLE_BITS_H
+
+#include <asm/metag_mem.h>
+
+/*
+ * Definitions for MMU descriptors
+ *
+ * These are the hardware bits in the MMCU pte entries.
+ * Derived from the Meta toolkit headers.
+ */
+#define _PAGE_PRESENT          MMCU_ENTRY_VAL_BIT
+#define _PAGE_WRITE            MMCU_ENTRY_WR_BIT
+#define _PAGE_PRIV             MMCU_ENTRY_PRIV_BIT
+/* Write combine bit - this can cause writes to occur out of order */
+#define _PAGE_WR_COMBINE       MMCU_ENTRY_WRC_BIT
+/* Sys coherent bit - this bit is never used by Linux */
+#define _PAGE_SYS_COHERENT     MMCU_ENTRY_SYS_BIT
+#define _PAGE_ALWAYS_ZERO_1    0x020
+#define _PAGE_CACHE_CTRL0      0x040
+#define _PAGE_CACHE_CTRL1      0x080
+#define _PAGE_ALWAYS_ZERO_2    0x100
+#define _PAGE_ALWAYS_ZERO_3    0x200
+#define _PAGE_ALWAYS_ZERO_4    0x400
+#define _PAGE_ALWAYS_ZERO_5    0x800
+
+/* These are software bits that we stuff into the gaps in the hardware
+ * pte entries that are not used.  Note, these DO get stored in the actual
+ * hardware, but the hardware just does not use them.
+ */
+#define _PAGE_ACCESSED         _PAGE_ALWAYS_ZERO_1
+#define _PAGE_DIRTY            _PAGE_ALWAYS_ZERO_2
+
+/* Pages owned, and protected by, the kernel. */
+#define _PAGE_KERNEL           _PAGE_PRIV
+
+/* No cacheing of this page */
+#define _PAGE_CACHE_WIN0       (MMCU_CWIN_UNCACHED << MMCU_ENTRY_CWIN_S)
+/* burst cacheing - good for data streaming */
+#define _PAGE_CACHE_WIN1       (MMCU_CWIN_BURST << MMCU_ENTRY_CWIN_S)
+/* One cache way per thread */
+#define _PAGE_CACHE_WIN2       (MMCU_CWIN_C1SET << MMCU_ENTRY_CWIN_S)
+/* Full on cacheing */
+#define _PAGE_CACHE_WIN3       (MMCU_CWIN_CACHED << MMCU_ENTRY_CWIN_S)
+
+#define _PAGE_CACHEABLE                (_PAGE_CACHE_WIN3 | _PAGE_WR_COMBINE)
+
+/* which bits are used for cache control ... */
+#define _PAGE_CACHE_MASK       (_PAGE_CACHE_CTRL0 | _PAGE_CACHE_CTRL1 | \
+                                _PAGE_WR_COMBINE)
+
+/* This is a mask of the bits that pte_modify is allowed to change. */
+#define _PAGE_CHG_MASK         (PAGE_MASK)
+
+#define _PAGE_SZ_SHIFT         1
+#define _PAGE_SZ_4K            (0x0)
+#define _PAGE_SZ_8K            (0x1 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_16K           (0x2 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_32K           (0x3 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_64K           (0x4 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_128K          (0x5 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_256K          (0x6 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_512K          (0x7 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_1M            (0x8 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_2M            (0x9 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_4M            (0xa << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_MASK          (0xf << _PAGE_SZ_SHIFT)
+
+#if defined(CONFIG_PAGE_SIZE_4K)
+#define _PAGE_SZ               (_PAGE_SZ_4K)
+#elif defined(CONFIG_PAGE_SIZE_8K)
+#define _PAGE_SZ               (_PAGE_SZ_8K)
+#elif defined(CONFIG_PAGE_SIZE_16K)
+#define _PAGE_SZ               (_PAGE_SZ_16K)
+#endif
+#define _PAGE_TABLE            (_PAGE_SZ | _PAGE_PRESENT)
+
+#if defined(CONFIG_HUGETLB_PAGE_SIZE_8K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_8K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_16K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_32K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_32K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_64K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_128K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_128K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_256K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_512K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_1M)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_2M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_2M)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_4M)
+#endif
+
+#endif /* _METAG_PGTABLE_BITS_H */
index d0604c0..ffa3a3a 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef _METAG_PGTABLE_H
 #define _METAG_PGTABLE_H
 
+#include <asm/pgtable-bits.h>
 #include <asm-generic/pgtable-nopmd.h>
 
 /* Invalid regions on Meta: 0x00000000-0x001FFFFF and 0xFFFF0000-0xFFFFFFFF */
 #endif
 
 /*
- * Definitions for MMU descriptors
- *
- * These are the hardware bits in the MMCU pte entries.
- * Derived from the Meta toolkit headers.
- */
-#define _PAGE_PRESENT          MMCU_ENTRY_VAL_BIT
-#define _PAGE_WRITE            MMCU_ENTRY_WR_BIT
-#define _PAGE_PRIV             MMCU_ENTRY_PRIV_BIT
-/* Write combine bit - this can cause writes to occur out of order */
-#define _PAGE_WR_COMBINE       MMCU_ENTRY_WRC_BIT
-/* Sys coherent bit - this bit is never used by Linux */
-#define _PAGE_SYS_COHERENT     MMCU_ENTRY_SYS_BIT
-#define _PAGE_ALWAYS_ZERO_1    0x020
-#define _PAGE_CACHE_CTRL0      0x040
-#define _PAGE_CACHE_CTRL1      0x080
-#define _PAGE_ALWAYS_ZERO_2    0x100
-#define _PAGE_ALWAYS_ZERO_3    0x200
-#define _PAGE_ALWAYS_ZERO_4    0x400
-#define _PAGE_ALWAYS_ZERO_5    0x800
-
-/* These are software bits that we stuff into the gaps in the hardware
- * pte entries that are not used.  Note, these DO get stored in the actual
- * hardware, but the hardware just does not use them.
- */
-#define _PAGE_ACCESSED         _PAGE_ALWAYS_ZERO_1
-#define _PAGE_DIRTY            _PAGE_ALWAYS_ZERO_2
-
-/* Pages owned, and protected by, the kernel. */
-#define _PAGE_KERNEL           _PAGE_PRIV
-
-/* No cacheing of this page */
-#define _PAGE_CACHE_WIN0       (MMCU_CWIN_UNCACHED << MMCU_ENTRY_CWIN_S)
-/* burst cacheing - good for data streaming */
-#define _PAGE_CACHE_WIN1       (MMCU_CWIN_BURST << MMCU_ENTRY_CWIN_S)
-/* One cache way per thread */
-#define _PAGE_CACHE_WIN2       (MMCU_CWIN_C1SET << MMCU_ENTRY_CWIN_S)
-/* Full on cacheing */
-#define _PAGE_CACHE_WIN3       (MMCU_CWIN_CACHED << MMCU_ENTRY_CWIN_S)
-
-#define _PAGE_CACHEABLE                (_PAGE_CACHE_WIN3 | _PAGE_WR_COMBINE)
-
-/* which bits are used for cache control ... */
-#define _PAGE_CACHE_MASK       (_PAGE_CACHE_CTRL0 | _PAGE_CACHE_CTRL1 | \
-                                _PAGE_WR_COMBINE)
-
-/* This is a mask of the bits that pte_modify is allowed to change. */
-#define _PAGE_CHG_MASK         (PAGE_MASK)
-
-#define _PAGE_SZ_SHIFT         1
-#define _PAGE_SZ_4K            (0x0)
-#define _PAGE_SZ_8K            (0x1 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_16K           (0x2 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_32K           (0x3 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_64K           (0x4 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_128K          (0x5 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_256K          (0x6 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_512K          (0x7 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_1M            (0x8 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_2M            (0x9 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_4M            (0xa << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_MASK          (0xf << _PAGE_SZ_SHIFT)
-
-#if defined(CONFIG_PAGE_SIZE_4K)
-#define _PAGE_SZ               (_PAGE_SZ_4K)
-#elif defined(CONFIG_PAGE_SIZE_8K)
-#define _PAGE_SZ               (_PAGE_SZ_8K)
-#elif defined(CONFIG_PAGE_SIZE_16K)
-#define _PAGE_SZ               (_PAGE_SZ_16K)
-#endif
-#define _PAGE_TABLE            (_PAGE_SZ | _PAGE_PRESENT)
-
-#if defined(CONFIG_HUGETLB_PAGE_SIZE_8K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_8K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_16K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_32K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_32K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_64K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_128K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_128K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_256K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_512K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_1M)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_2M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_2M)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_4M)
-#endif
-
-/*
  * The Linux memory management assumes a three-level page table setup. On
  * Meta, we use that, but "fold" the mid level into the top-level page
  * table.
index 3761311..e0bb972 100644 (file)
@@ -1,6 +1,5 @@
 include include/uapi/asm-generic/Kbuild.asm
 
 header-y += elf.h
-header-y += ucontext.h
 
 generic-y += ucontext.h
index 0d231ad..0c9b6af 100644 (file)
@@ -126,7 +126,6 @@ good_area:
                break;
        }
 
-survive:
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
@@ -220,11 +219,6 @@ no_context:
  */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       if (is_global_init(tsk)) {
-               yield();
-               down_read(&mm->mmap_sem);
-               goto survive;
-       }
        if (!user_mode(regs))
                goto no_context;
        pagefault_out_of_memory();
index f213f5b..d174372 100644 (file)
@@ -26,7 +26,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
        if (likely(pgd != NULL)) {
                memset(pgd, 0, PAGE_SIZE<<PGD_ALLOC_ORDER);
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
                actual_pgd += PTRS_PER_PGD;
                /* Populate first pmd with allocated memory.  We mark it
                 * with PxD_FLAG_ATTACHED as a signal to the system that this
@@ -45,7 +45,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
        pgd -= PTRS_PER_PGD;
 #endif
        free_pages((unsigned long)pgd, PGD_ALLOC_ORDER);
@@ -72,12 +72,15 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 
 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
-#ifdef CONFIG_64BIT
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
-               /* This is the permanent pmd attached to the pgd;
-                * cannot free it */
+               /*
+                * This is the permanent pmd attached to the pgd;
+                * cannot free it.
+                * Increment the counter to compensate for the decrement
+                * done by generic mm code.
+                */
+               mm_inc_nr_pmds(mm);
                return;
-#endif
        free_pages((unsigned long)pmd, PMD_ORDER);
 }
 
@@ -99,7 +102,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 static inline void
 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 {
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
        /* preserve the gateway marker if this is the beginning of
         * the permanent pmd */
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
index 5a8997d..8eefb12 100644 (file)
@@ -55,8 +55,8 @@
 #define ENTRY_COMP(_name_) .word sys_##_name_
 #endif
 
-       ENTRY_SAME(restart_syscall)     /* 0 */
-       ENTRY_SAME(exit)
+90:    ENTRY_SAME(restart_syscall)     /* 0 */
+91:    ENTRY_SAME(exit)
        ENTRY_SAME(fork_wrapper)
        ENTRY_SAME(read)
        ENTRY_SAME(write)
        ENTRY_SAME(bpf)
        ENTRY_COMP(execveat)
 
-       /* Nothing yet */
+
+.ifne (. - 90b) - (__NR_Linux_syscalls * (91b - 90b))
+.error "size of syscall table does not fit value of __NR_Linux_syscalls"
+.endif
 
 #undef ENTRY_SAME
 #undef ENTRY_DIFF
index 2bf8e93..4c8ad59 100644 (file)
@@ -55,7 +55,7 @@ static inline cpumask_t cpu_thread_mask_to_cores(const struct cpumask *threads)
 
 static inline int cpu_nr_cores(void)
 {
-       return NR_CPUS >> threads_shift;
+       return nr_cpu_ids >> threads_shift;
 }
 
 static inline cpumask_t cpu_online_cores_map(void)
index 03cd858..4cbe23a 100644 (file)
 #define PPC_INST_MFSPR_PVR_MASK                0xfc1fffff
 #define PPC_INST_MFTMR                 0x7c0002dc
 #define PPC_INST_MSGSND                        0x7c00019c
+#define PPC_INST_MSGCLR                        0x7c0001dc
 #define PPC_INST_MSGSNDP               0x7c00011c
 #define PPC_INST_MTTMR                 0x7c0003dc
 #define PPC_INST_NOP                   0x60000000
                                        ___PPC_RB(b) | __PPC_EH(eh))
 #define PPC_MSGSND(b)          stringify_in_c(.long PPC_INST_MSGSND | \
                                        ___PPC_RB(b))
+#define PPC_MSGCLR(b)          stringify_in_c(.long PPC_INST_MSGCLR | \
+                                       ___PPC_RB(b))
 #define PPC_MSGSNDP(b)         stringify_in_c(.long PPC_INST_MSGSNDP | \
                                        ___PPC_RB(b))
 #define PPC_POPCNTB(a, s)      stringify_in_c(.long PPC_INST_POPCNTB | \
index 1c874fb..af56b5c 100644 (file)
 #define   SRR1_ISI_N_OR_G      0x10000000 /* ISI: Access is no-exec or G */
 #define   SRR1_ISI_PROT                0x08000000 /* ISI: Other protection fault */
 #define   SRR1_WAKEMASK                0x00380000 /* reason for wakeup */
+#define   SRR1_WAKEMASK_P8     0x003c0000 /* reason for wakeup on POWER8 */
 #define   SRR1_WAKESYSERR      0x00300000 /* System error */
 #define   SRR1_WAKEEE          0x00200000 /* External interrupt */
 #define   SRR1_WAKEMT          0x00280000 /* mtctrl */
 #define          SRR1_WAKEHMI          0x00280000 /* Hypervisor maintenance */
 #define   SRR1_WAKEDEC         0x00180000 /* Decrementer interrupt */
+#define   SRR1_WAKEDBELL       0x00140000 /* Privileged doorbell on P8 */
 #define   SRR1_WAKETHERM       0x00100000 /* Thermal management interrupt */
 #define          SRR1_WAKERESET        0x00100000 /* System reset */
+#define   SRR1_WAKEHDBELL      0x000c0000 /* Hypervisor doorbell on P8 */
 #define          SRR1_WAKESTATE        0x00030000 /* Powersave exit mask [46:47] */
 #define          SRR1_WS_DEEPEST       0x00030000 /* Some resources not maintained,
                                          * may not be recoverable */
index f337666..f830468 100644 (file)
@@ -437,6 +437,26 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check_early    = __machine_check_early_realmode_p8,
                .platform               = "power8",
        },
+       {       /* Power8NVL */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x004c0000,
+               .cpu_name               = "POWER8NVL (raw)",
+               .cpu_features           = CPU_FTRS_POWER8,
+               .cpu_user_features      = COMMON_USER_POWER8,
+               .cpu_user_features2     = COMMON_USER2_POWER8,
+               .mmu_features           = MMU_FTRS_POWER8,
+               .icache_bsize           = 128,
+               .dcache_bsize           = 128,
+               .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_IBM,
+               .oprofile_cpu_type      = "ppc64/power8",
+               .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 DD1: Does not support doorbell IPIs */
                .pvr_mask               = 0xffffff00,
                .pvr_value              = 0x004d0100,
index f421781..2128f3a 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/dbell.h>
 #include <asm/irq_regs.h>
+#include <asm/kvm_ppc.h>
 
 #ifdef CONFIG_SMP
 void doorbell_setup_this_cpu(void)
@@ -41,6 +42,7 @@ void doorbell_exception(struct pt_regs *regs)
 
        may_hard_irq_enable();
 
+       kvmppc_set_host_ipi(smp_processor_id(), 0);
        __this_cpu_inc(irq_stat.doorbell_irqs);
 
        smp_ipi_demux();
index c2df815..9519e6b 100644 (file)
@@ -1408,7 +1408,7 @@ machine_check_handle_early:
        bne     9f                      /* continue in V mode if we are. */
 
 5:
-#ifdef CONFIG_KVM_BOOK3S_64_HV
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
        /*
         * We are coming from kernel context. Check if we are coming from
         * guest. if yes, then we can continue. We will fall through
index de4018a..de74756 100644 (file)
@@ -636,7 +636,7 @@ static int kvmppc_get_yield_count(struct kvm_vcpu *vcpu)
        spin_lock(&vcpu->arch.vpa_update_lock);
        lppaca = (struct lppaca *)vcpu->arch.vpa.pinned_addr;
        if (lppaca)
-               yield_count = lppaca->yield_count;
+               yield_count = be32_to_cpu(lppaca->yield_count);
        spin_unlock(&vcpu->arch.vpa_update_lock);
        return yield_count;
 }
@@ -942,20 +942,20 @@ static int kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu,
 static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                bool preserve_top32)
 {
+       struct kvm *kvm = vcpu->kvm;
        struct kvmppc_vcore *vc = vcpu->arch.vcore;
        u64 mask;
 
+       mutex_lock(&kvm->lock);
        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;
@@ -964,7 +964,6 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                        else
                                vcpu->arch.intr_msr &= ~MSR_LE;
                }
-               mutex_unlock(&kvm->lock);
        }
 
        /*
@@ -981,6 +980,7 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                mask &= 0xFFFFFFFF;
        vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask);
        spin_unlock(&vc->lock);
+       mutex_unlock(&kvm->lock);
 }
 
 static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
index bb94e6f..6cbf163 100644 (file)
@@ -1005,6 +1005,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        /* Save HEIR (HV emulation assist reg) in emul_inst
           if this is an HEI (HV emulation interrupt, e40) */
        li      r3,KVM_INST_FETCH_FAILED
+       stw     r3,VCPU_LAST_INST(r9)
        cmpwi   r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
        bne     11f
        mfspr   r3,SPRN_HEIR
index fc34025..38a4508 100644 (file)
@@ -33,6 +33,8 @@
 #include <asm/runlatch.h>
 #include <asm/code-patching.h>
 #include <asm/dbell.h>
+#include <asm/kvm_ppc.h>
+#include <asm/ppc-opcode.h>
 
 #include "powernv.h"
 
@@ -149,7 +151,7 @@ static int pnv_smp_cpu_disable(void)
 static void pnv_smp_cpu_kill_self(void)
 {
        unsigned int cpu;
-       unsigned long srr1;
+       unsigned long srr1, wmask;
        u32 idle_states;
 
        /* Standard hot unplug procedure */
@@ -161,6 +163,10 @@ static void pnv_smp_cpu_kill_self(void)
        generic_set_cpu_dead(cpu);
        smp_wmb();
 
+       wmask = SRR1_WAKEMASK;
+       if (cpu_has_feature(CPU_FTR_ARCH_207S))
+               wmask = SRR1_WAKEMASK_P8;
+
        idle_states = pnv_get_supported_cpuidle_states();
        /* We don't want to take decrementer interrupts while we are offline,
         * so clear LPCR:PECE1. We keep PECE2 enabled.
@@ -191,10 +197,14 @@ static void pnv_smp_cpu_kill_self(void)
                 * having finished executing in a KVM guest, then srr1
                 * contains 0.
                 */
-               if ((srr1 & SRR1_WAKEMASK) == SRR1_WAKEEE) {
+               if ((srr1 & wmask) == SRR1_WAKEEE) {
                        icp_native_flush_interrupt();
                        local_paca->irq_happened &= PACA_IRQ_HARD_DIS;
                        smp_mb();
+               } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
+                       unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
+                       asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
+                       kvmppc_set_host_ipi(cpu, 0);
                }
 
                if (cpu_core_split_required())
index 90cf3dc..8f35d52 100644 (file)
 static struct kobject *mobility_kobj;
 
 struct update_props_workarea {
-       u32 phandle;
-       u32 state;
-       u64 reserved;
-       u32 nprops;
+       __be32 phandle;
+       __be32 state;
+       __be64 reserved;
+       __be32 nprops;
 } __packed;
 
 #define NODE_ACTION_MASK       0xff000000
@@ -54,11 +54,11 @@ static int mobility_rtas_call(int token, char *buf, s32 scope)
        return rc;
 }
 
-static int delete_dt_node(u32 phandle)
+static int delete_dt_node(__be32 phandle)
 {
        struct device_node *dn;
 
-       dn = of_find_node_by_phandle(phandle);
+       dn = of_find_node_by_phandle(be32_to_cpu(phandle));
        if (!dn)
                return -ENOENT;
 
@@ -127,7 +127,7 @@ static int update_dt_property(struct device_node *dn, struct property **prop,
        return 0;
 }
 
-static int update_dt_node(u32 phandle, s32 scope)
+static int update_dt_node(__be32 phandle, s32 scope)
 {
        struct update_props_workarea *upwa;
        struct device_node *dn;
@@ -136,6 +136,7 @@ static int update_dt_node(u32 phandle, s32 scope)
        char *prop_data;
        char *rtas_buf;
        int update_properties_token;
+       u32 nprops;
        u32 vd;
 
        update_properties_token = rtas_token("ibm,update-properties");
@@ -146,7 +147,7 @@ static int update_dt_node(u32 phandle, s32 scope)
        if (!rtas_buf)
                return -ENOMEM;
 
-       dn = of_find_node_by_phandle(phandle);
+       dn = of_find_node_by_phandle(be32_to_cpu(phandle));
        if (!dn) {
                kfree(rtas_buf);
                return -ENOENT;
@@ -162,6 +163,7 @@ static int update_dt_node(u32 phandle, s32 scope)
                        break;
 
                prop_data = rtas_buf + sizeof(*upwa);
+               nprops = be32_to_cpu(upwa->nprops);
 
                /* On the first call to ibm,update-properties for a node the
                 * the first property value descriptor contains an empty
@@ -170,17 +172,17 @@ static int update_dt_node(u32 phandle, s32 scope)
                 */
                if (*prop_data == 0) {
                        prop_data++;
-                       vd = *(u32 *)prop_data;
+                       vd = be32_to_cpu(*(__be32 *)prop_data);
                        prop_data += vd + sizeof(vd);
-                       upwa->nprops--;
+                       nprops--;
                }
 
-               for (i = 0; i < upwa->nprops; i++) {
+               for (i = 0; i < nprops; i++) {
                        char *prop_name;
 
                        prop_name = prop_data;
                        prop_data += strlen(prop_name) + 1;
-                       vd = *(u32 *)prop_data;
+                       vd = be32_to_cpu(*(__be32 *)prop_data);
                        prop_data += sizeof(vd);
 
                        switch (vd) {
@@ -212,13 +214,13 @@ static int update_dt_node(u32 phandle, s32 scope)
        return 0;
 }
 
-static int add_dt_node(u32 parent_phandle, u32 drc_index)
+static int add_dt_node(__be32 parent_phandle, __be32 drc_index)
 {
        struct device_node *dn;
        struct device_node *parent_dn;
        int rc;
 
-       parent_dn = of_find_node_by_phandle(parent_phandle);
+       parent_dn = of_find_node_by_phandle(be32_to_cpu(parent_phandle));
        if (!parent_dn)
                return -ENOENT;
 
@@ -237,7 +239,7 @@ static int add_dt_node(u32 parent_phandle, u32 drc_index)
 int pseries_devicetree_update(s32 scope)
 {
        char *rtas_buf;
-       u32 *data;
+       __be32 *data;
        int update_nodes_token;
        int rc;
 
@@ -254,17 +256,17 @@ int pseries_devicetree_update(s32 scope)
                if (rc && rc != 1)
                        break;
 
-               data = (u32 *)rtas_buf + 4;
-               while (*data & NODE_ACTION_MASK) {
+               data = (__be32 *)rtas_buf + 4;
+               while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
                        int i;
-                       u32 action = *data & NODE_ACTION_MASK;
-                       int node_count = *data & NODE_COUNT_MASK;
+                       u32 action = be32_to_cpu(*data) & NODE_ACTION_MASK;
+                       u32 node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
 
                        data++;
 
                        for (i = 0; i < node_count; i++) {
-                               u32 phandle = *data++;
-                               u32 drc_index;
+                               __be32 phandle = *data++;
+                               __be32 drc_index;
 
                                switch (action) {
                                case DELETE_DT_NODE:
index c9df40b..c9c875d 100644 (file)
@@ -211,7 +211,7 @@ do {                                                                \
 
 extern unsigned long mmap_rnd_mask;
 
-#define STACK_RND_MASK (mmap_rnd_mask)
+#define STACK_RND_MASK (test_thread_flag(TIF_31BIT) ? 0x7ff : mmap_rnd_mask)
 
 #define ARCH_DLINFO                                                        \
 do {                                                                       \
index 82c1989..6c79f1b 100644 (file)
 
 unsigned long ftrace_plt;
 
+static inline void ftrace_generate_orig_insn(struct ftrace_insn *insn)
+{
+#ifdef CC_USING_HOTPATCH
+       /* brcl 0,0 */
+       insn->opc = 0xc004;
+       insn->disp = 0;
+#else
+       /* stg r14,8(r15) */
+       insn->opc = 0xe3e0;
+       insn->disp = 0xf0080024;
+#endif
+}
+
+static inline int is_kprobe_on_ftrace(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       if (insn->opc == BREAKPOINT_INSTRUCTION)
+               return 1;
+#endif
+       return 0;
+}
+
+static inline void ftrace_generate_kprobe_nop_insn(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       insn->opc = BREAKPOINT_INSTRUCTION;
+       insn->disp = KPROBE_ON_FTRACE_NOP;
+#endif
+}
+
+static inline void ftrace_generate_kprobe_call_insn(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       insn->opc = BREAKPOINT_INSTRUCTION;
+       insn->disp = KPROBE_ON_FTRACE_CALL;
+#endif
+}
+
 int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
                       unsigned long addr)
 {
@@ -72,16 +110,9 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
                return -EFAULT;
        if (addr == MCOUNT_ADDR) {
                /* Initial code replacement */
-#ifdef CC_USING_HOTPATCH
-               /* We expect to see brcl 0,0 */
-               ftrace_generate_nop_insn(&orig);
-#else
-               /* We expect to see stg r14,8(r15) */
-               orig.opc = 0xe3e0;
-               orig.disp = 0xf0080024;
-#endif
+               ftrace_generate_orig_insn(&orig);
                ftrace_generate_nop_insn(&new);
-       } else if (old.opc == BREAKPOINT_INSTRUCTION) {
+       } else if (is_kprobe_on_ftrace(&old)) {
                /*
                 * If we find a breakpoint instruction, a kprobe has been
                 * placed at the beginning of the function. We write the
@@ -89,9 +120,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
                 * bytes of the original instruction so that the kprobes
                 * handler can execute a nop, if it reaches this breakpoint.
                 */
-               new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
-               orig.disp = KPROBE_ON_FTRACE_CALL;
-               new.disp = KPROBE_ON_FTRACE_NOP;
+               ftrace_generate_kprobe_call_insn(&orig);
+               ftrace_generate_kprobe_nop_insn(&new);
        } else {
                /* Replace ftrace call with a nop. */
                ftrace_generate_call_insn(&orig, rec->ip);
@@ -111,7 +141,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 
        if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
                return -EFAULT;
-       if (old.opc == BREAKPOINT_INSTRUCTION) {
+       if (is_kprobe_on_ftrace(&old)) {
                /*
                 * If we find a breakpoint instruction, a kprobe has been
                 * placed at the beginning of the function. We write the
@@ -119,9 +149,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
                 * bytes of the original instruction so that the kprobes
                 * handler can execute a brasl if it reaches this breakpoint.
                 */
-               new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
-               orig.disp = KPROBE_ON_FTRACE_NOP;
-               new.disp = KPROBE_ON_FTRACE_CALL;
+               ftrace_generate_kprobe_nop_insn(&orig);
+               ftrace_generate_kprobe_call_insn(&new);
        } else {
                /* Replace nop with an ftrace call. */
                ftrace_generate_nop_insn(&orig);
index c3f8d15..e6a1578 100644 (file)
@@ -1415,7 +1415,7 @@ CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC_DIAG, PERF_EVENT_CPUM_SF_DIAG);
 
 static struct attribute *cpumsf_pmu_events_attr[] = {
        CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC),
-       CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG),
+       NULL,
        NULL,
 };
 
@@ -1606,8 +1606,11 @@ static int __init init_cpum_sampling_pmu(void)
                return -EINVAL;
        }
 
-       if (si.ad)
+       if (si.ad) {
                sfb_set_limits(CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB);
+               cpumsf_pmu_events_attr[1] =
+                       CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG);
+       }
 
        sfdbg = debug_register(KMSG_COMPONENT, 2, 1, 80);
        if (!sfdbg)
index 6b09fdf..ca62946 100644 (file)
@@ -177,6 +177,17 @@ restart_entry:
        lhi     %r1,1
        sigp    %r1,%r0,SIGP_SET_ARCHITECTURE
        sam64
+#ifdef CONFIG_SMP
+       larl    %r1,smp_cpu_mt_shift
+       icm     %r1,15,0(%r1)
+       jz      smt_done
+       llgfr   %r1,%r1
+smt_loop:
+       sigp    %r1,%r0,SIGP_SET_MULTI_THREADING
+       brc     8,smt_done                      /* accepted */
+       brc     2,smt_loop                      /* busy, try again */
+smt_done:
+#endif
        larl    %r1,.Lnew_pgm_check_psw
        lpswe   0(%r1)
 pgm_check_entry:
index f6579cf..19e17bd 100644 (file)
@@ -165,7 +165,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_ONE_REG:
        case KVM_CAP_ENABLE_CAP:
        case KVM_CAP_S390_CSS_SUPPORT:
-       case KVM_CAP_IRQFD:
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_DEVICE_CTRL:
        case KVM_CAP_ENABLE_CAP_VM:
index 96ac69c..efb00ec 100644 (file)
@@ -86,6 +86,9 @@ config ARCH_DEFCONFIG
        default "arch/sparc/configs/sparc32_defconfig" if SPARC32
        default "arch/sparc/configs/sparc64_defconfig" if SPARC64
 
+config ARCH_PROC_KCORE_TEXT
+       def_bool y
+
 config IOMMU_HELPER
        bool
        default y if SPARC64
index 4f6725f..f5b6537 100644 (file)
@@ -2957,6 +2957,17 @@ unsigned long sun4v_t5_set_perfreg(unsigned long reg_num,
                                   unsigned long reg_val);
 #endif
 
+
+#define HV_FAST_M7_GET_PERFREG 0x43
+#define HV_FAST_M7_SET_PERFREG 0x44
+
+#ifndef        __ASSEMBLY__
+unsigned long sun4v_m7_get_perfreg(unsigned long reg_num,
+                                     unsigned long *reg_val);
+unsigned long sun4v_m7_set_perfreg(unsigned long reg_num,
+                                     unsigned long reg_val);
+#endif
+
 /* Function numbers for HV_CORE_TRAP.  */
 #define HV_CORE_SET_VER                        0x00
 #define HV_CORE_PUTCHAR                        0x01
@@ -2981,6 +2992,7 @@ unsigned long sun4v_t5_set_perfreg(unsigned long reg_num,
 #define HV_GRP_SDIO                    0x0108
 #define HV_GRP_SDIO_ERR                        0x0109
 #define HV_GRP_REBOOT_DATA             0x0110
+#define HV_GRP_M7_PERF                 0x0114
 #define HV_GRP_NIAG_PERF               0x0200
 #define HV_GRP_FIRE_PERF               0x0201
 #define HV_GRP_N2_CPU                  0x0202
index 9b672be..50d4840 100644 (file)
@@ -407,16 +407,16 @@ static inline void iounmap(volatile void __iomem *addr)
 {
 }
 
-#define ioread8(X)                     readb(X)
-#define ioread16(X)                    readw(X)
-#define ioread16be(X)                  __raw_readw(X)
-#define ioread32(X)                    readl(X)
-#define ioread32be(X)                  __raw_readl(X)
-#define iowrite8(val,X)                        writeb(val,X)
-#define iowrite16(val,X)               writew(val,X)
-#define iowrite16be(val,X)             __raw_writew(val,X)
-#define iowrite32(val,X)               writel(val,X)
-#define iowrite32be(val,X)             __raw_writel(val,X)
+#define ioread8                        readb
+#define ioread16               readw
+#define ioread16be             __raw_readw
+#define ioread32               readl
+#define ioread32be             __raw_readl
+#define iowrite8               writeb
+#define iowrite16              writew
+#define iowrite16be            __raw_writew
+#define iowrite32              writel
+#define iowrite32be            __raw_writel
 
 /* Create a virtual mapping cookie for an IO port range */
 void __iomem *ioport_map(unsigned long port, unsigned int nr);
index c100dc2..176fa0a 100644 (file)
@@ -12,7 +12,6 @@
 extern int this_is_starfire;
 
 void check_if_starfire(void);
-int starfire_hard_smp_processor_id(void);
 void starfire_hookup(int);
 unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
 
index 88d322b..07cc49e 100644 (file)
@@ -98,11 +98,7 @@ void sun4v_do_mna(struct pt_regs *regs,
 void do_privop(struct pt_regs *regs);
 void do_privact(struct pt_regs *regs);
 void do_cee(struct pt_regs *regs);
-void do_cee_tl1(struct pt_regs *regs);
-void do_dae_tl1(struct pt_regs *regs);
-void do_iae_tl1(struct pt_regs *regs);
 void do_div0_tl1(struct pt_regs *regs);
-void do_fpdis_tl1(struct pt_regs *regs);
 void do_fpieee_tl1(struct pt_regs *regs);
 void do_fpother_tl1(struct pt_regs *regs);
 void do_ill_tl1(struct pt_regs *regs);
index 5c55145..662500f 100644 (file)
@@ -48,6 +48,7 @@ static struct api_info api_table[] = {
        { .group = HV_GRP_VT_CPU,                               },
        { .group = HV_GRP_T5_CPU,                               },
        { .group = HV_GRP_DIAG,         .flags = FLAG_PRE_API   },
+       { .group = HV_GRP_M7_PERF,                              },
 };
 
 static DEFINE_SPINLOCK(hvapi_lock);
index caedf83..afbaba5 100644 (file)
@@ -837,3 +837,19 @@ ENTRY(sun4v_t5_set_perfreg)
        retl
         nop
 ENDPROC(sun4v_t5_set_perfreg)
+
+ENTRY(sun4v_m7_get_perfreg)
+       mov     %o1, %o4
+       mov     HV_FAST_M7_GET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       stx     %o1, [%o4]
+       retl
+       nop
+ENDPROC(sun4v_m7_get_perfreg)
+
+ENTRY(sun4v_m7_set_perfreg)
+       mov     HV_FAST_M7_SET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       retl
+       nop
+ENDPROC(sun4v_m7_set_perfreg)
index 7e967c8..eb978c7 100644 (file)
@@ -217,6 +217,31 @@ static const struct pcr_ops n5_pcr_ops = {
        .pcr_nmi_disable        = PCR_N4_PICNPT,
 };
 
+static u64 m7_pcr_read(unsigned long reg_num)
+{
+       unsigned long val;
+
+       (void) sun4v_m7_get_perfreg(reg_num, &val);
+
+       return val;
+}
+
+static void m7_pcr_write(unsigned long reg_num, u64 val)
+{
+       (void) sun4v_m7_set_perfreg(reg_num, val);
+}
+
+static const struct pcr_ops m7_pcr_ops = {
+       .read_pcr               = m7_pcr_read,
+       .write_pcr              = m7_pcr_write,
+       .read_pic               = n4_pic_read,
+       .write_pic              = n4_pic_write,
+       .nmi_picl_value         = n4_picl_value,
+       .pcr_nmi_enable         = (PCR_N4_PICNPT | PCR_N4_STRACE |
+                                  PCR_N4_UTRACE | PCR_N4_TOE |
+                                  (26 << PCR_N4_SL_SHIFT)),
+       .pcr_nmi_disable        = PCR_N4_PICNPT,
+};
 
 static unsigned long perf_hsvc_group;
 static unsigned long perf_hsvc_major;
@@ -248,6 +273,10 @@ static int __init register_perf_hsvc(void)
                        perf_hsvc_group = HV_GRP_T5_CPU;
                        break;
 
+               case SUN4V_CHIP_SPARC_M7:
+                       perf_hsvc_group = HV_GRP_M7_PERF;
+                       break;
+
                default:
                        return -ENODEV;
                }
@@ -293,6 +322,10 @@ static int __init setup_sun4v_pcr_ops(void)
                pcr_ops = &n5_pcr_ops;
                break;
 
+       case SUN4V_CHIP_SPARC_M7:
+               pcr_ops = &m7_pcr_ops;
+               break;
+
        default:
                ret = -ENODEV;
                break;
index 46a5e45..86eebfa 100644 (file)
@@ -792,6 +792,42 @@ static const struct sparc_pmu niagara4_pmu = {
        .num_pic_regs   = 4,
 };
 
+static void sparc_m7_write_pmc(int idx, u64 val)
+{
+       u64 pcr;
+
+       pcr = pcr_ops->read_pcr(idx);
+       /* ensure ov and ntc are reset */
+       pcr &= ~(PCR_N4_OV | PCR_N4_NTC);
+
+       pcr_ops->write_pic(idx, val & 0xffffffff);
+
+       pcr_ops->write_pcr(idx, pcr);
+}
+
+static const struct sparc_pmu sparc_m7_pmu = {
+       .event_map      = niagara4_event_map,
+       .cache_map      = &niagara4_cache_map,
+       .max_events     = ARRAY_SIZE(niagara4_perfmon_event_map),
+       .read_pmc       = sparc_vt_read_pmc,
+       .write_pmc      = sparc_m7_write_pmc,
+       .upper_shift    = 5,
+       .lower_shift    = 5,
+       .event_mask     = 0x7ff,
+       .user_bit       = PCR_N4_UTRACE,
+       .priv_bit       = PCR_N4_STRACE,
+
+       /* We explicitly don't support hypervisor tracing. */
+       .hv_bit         = 0,
+
+       .irq_bit        = PCR_N4_TOE,
+       .upper_nop      = 0,
+       .lower_nop      = 0,
+       .flags          = 0,
+       .max_hw_events  = 4,
+       .num_pcrs       = 4,
+       .num_pic_regs   = 4,
+};
 static const struct sparc_pmu *sparc_pmu __read_mostly;
 
 static u64 event_encoding(u64 event_id, int idx)
@@ -960,6 +996,8 @@ out:
        cpuc->pcr[0] |= cpuc->event[0]->hw.config_base;
 }
 
+static void sparc_pmu_start(struct perf_event *event, int flags);
+
 /* On this PMU each PIC has it's own PCR control register.  */
 static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc)
 {
@@ -972,20 +1010,13 @@ static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc)
                struct perf_event *cp = cpuc->event[i];
                struct hw_perf_event *hwc = &cp->hw;
                int idx = hwc->idx;
-               u64 enc;
 
                if (cpuc->current_idx[i] != PIC_NO_INDEX)
                        continue;
 
-               sparc_perf_event_set_period(cp, hwc, idx);
                cpuc->current_idx[i] = idx;
 
-               enc = perf_event_get_enc(cpuc->events[i]);
-               cpuc->pcr[idx] &= ~mask_for_index(idx);
-               if (hwc->state & PERF_HES_STOPPED)
-                       cpuc->pcr[idx] |= nop_for_index(idx);
-               else
-                       cpuc->pcr[idx] |= event_encoding(enc, idx);
+               sparc_pmu_start(cp, PERF_EF_RELOAD);
        }
 out:
        for (i = 0; i < cpuc->n_events; i++) {
@@ -1101,7 +1132,6 @@ static void sparc_pmu_del(struct perf_event *event, int _flags)
        int i;
 
        local_irq_save(flags);
-       perf_pmu_disable(event->pmu);
 
        for (i = 0; i < cpuc->n_events; i++) {
                if (event == cpuc->event[i]) {
@@ -1127,7 +1157,6 @@ static void sparc_pmu_del(struct perf_event *event, int _flags)
                }
        }
 
-       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
 }
 
@@ -1361,7 +1390,6 @@ static int sparc_pmu_add(struct perf_event *event, int ef_flags)
        unsigned long flags;
 
        local_irq_save(flags);
-       perf_pmu_disable(event->pmu);
 
        n0 = cpuc->n_events;
        if (n0 >= sparc_pmu->max_hw_events)
@@ -1394,7 +1422,6 @@ nocheck:
 
        ret = 0;
 out:
-       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
        return ret;
 }
@@ -1667,6 +1694,10 @@ static bool __init supported_pmu(void)
                sparc_pmu = &niagara4_pmu;
                return true;
        }
+       if (!strcmp(sparc_pmu_type, "sparc-m7")) {
+               sparc_pmu = &sparc_m7_pmu;
+               return true;
+       }
        return false;
 }
 
index 0be7bf9..46a5964 100644 (file)
@@ -287,6 +287,8 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
                        printk("             TPC[%lx] O7[%lx] I7[%lx] RPC[%lx]\n",
                               gp->tpc, gp->o7, gp->i7, gp->rpc);
                }
+
+               touch_nmi_watchdog();
        }
 
        memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
@@ -362,6 +364,8 @@ static void pmu_snapshot_all_cpus(void)
                       (cpu == this_cpu ? '*' : ' '), cpu,
                       pp->pcr[0], pp->pcr[1], pp->pcr[2], pp->pcr[3],
                       pp->pic[0], pp->pic[1], pp->pic[2], pp->pic[3]);
+
+               touch_nmi_watchdog();
        }
 
        memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
index da6f1a7..61139d9 100644 (file)
@@ -1406,11 +1406,32 @@ void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
        scheduler_ipi();
 }
 
-/* This is a nop because we capture all other cpus
- * anyways when making the PROM active.
- */
+static void stop_this_cpu(void *dummy)
+{
+       prom_stopself();
+}
+
 void smp_send_stop(void)
 {
+       int cpu;
+
+       if (tlb_type == hypervisor) {
+               for_each_online_cpu(cpu) {
+                       if (cpu == smp_processor_id())
+                               continue;
+#ifdef CONFIG_SUN_LDOMS
+                       if (ldom_domaining_enabled) {
+                               unsigned long hv_err;
+                               hv_err = sun4v_cpu_stop(cpu);
+                               if (hv_err)
+                                       printk(KERN_ERR "sun4v_cpu_stop() "
+                                              "failed err=%lu\n", hv_err);
+                       } else
+#endif
+                               prom_stopcpu_cpuid(cpu);
+               }
+       } else
+               smp_call_function(stop_this_cpu, NULL, 0);
 }
 
 /**
index 82281a5..167fdfd 100644 (file)
@@ -28,11 +28,6 @@ void check_if_starfire(void)
                this_is_starfire = 1;
 }
 
-int starfire_hard_smp_processor_id(void)
-{
-       return upa_readl(0x1fff40000d0UL);
-}
-
 /*
  * Each Starfire board has 32 registers which perform translation
  * and delivery of traditional interrupt packets into the extended
index c85403d..30e7ddb 100644 (file)
@@ -333,7 +333,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
        long err;
 
        /* No need for backward compatibility. We can start fresh... */
-       if (call <= SEMCTL) {
+       if (call <= SEMTIMEDOP) {
                switch (call) {
                case SEMOP:
                        err = sys_semtimedop(first, ptr,
index a27651e..0e69974 100644 (file)
@@ -2427,6 +2427,8 @@ void __noreturn die_if_kernel(char *str, struct pt_regs *regs)
                }
                user_instruction_dump ((unsigned int __user *) regs->tpc);
        }
+       if (panic_on_oops)
+               panic("Fatal exception");
        if (regs->tstate & TSTATE_PRIV)
                do_exit(SIGKILL);
        do_exit(SIGSEGV);
@@ -2564,27 +2566,6 @@ void do_cee(struct pt_regs *regs)
        die_if_kernel("TL0: Cache Error Exception", regs);
 }
 
-void do_cee_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Cache Error Exception", regs);
-}
-
-void do_dae_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Data Access Exception", regs);
-}
-
-void do_iae_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Instruction Access Exception", regs);
-}
-
 void do_div0_tl1(struct pt_regs *regs)
 {
        exception_enter();
@@ -2592,13 +2573,6 @@ void do_div0_tl1(struct pt_regs *regs)
        die_if_kernel("TL1: DIV0 Exception", regs);
 }
 
-void do_fpdis_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: FPU Disabled", regs);
-}
-
 void do_fpieee_tl1(struct pt_regs *regs)
 {
        exception_enter();
index b7f6334..857ad4f 100644 (file)
@@ -8,9 +8,11 @@
 
        .text
 ENTRY(memmove) /* o0=dst o1=src o2=len */
-       mov             %o0, %g1
+       brz,pn          %o2, 99f
+        mov            %o0, %g1
+
        cmp             %o0, %o1
-       bleu,pt         %xcc, memcpy
+       bleu,pt         %xcc, 2f
         add            %o1, %o2, %g7
        cmp             %g7, %o0
        bleu,pt         %xcc, memcpy
@@ -24,7 +26,34 @@ ENTRY(memmove) /* o0=dst o1=src o2=len */
        stb             %g7, [%o0]
        bne,pt          %icc, 1b
         sub            %o0, 1, %o0
-
+99:
        retl
         mov            %g1, %o0
+
+       /* We can't just call memcpy for these memmove cases.  On some
+        * chips the memcpy uses cache initializing stores and when dst
+        * and src are close enough, those can clobber the source data
+        * before we've loaded it in.
+        */
+2:     or              %o0, %o1, %g7
+       or              %o2, %g7, %g7
+       andcc           %g7, 0x7, %g0
+       bne,pn          %xcc, 4f
+        nop
+
+3:     ldx             [%o1], %g7
+       add             %o1, 8, %o1
+       subcc           %o2, 8, %o2
+       add             %o0, 8, %o0
+       bne,pt          %icc, 3b
+        stx            %g7, [%o0 - 0x8]
+       ba,a,pt         %xcc, 99b
+
+4:     ldub            [%o1], %g7
+       add             %o1, 1, %o1
+       subcc           %o2, 1, %o2
+       add             %o0, 1, %o0
+       bne,pt          %icc, 4b
+        stb            %g7, [%o0 - 0x1]
+       ba,a,pt         %xcc, 99b
 ENDPROC(memmove)
index 3ea267c..4ca0d6b 100644 (file)
@@ -2820,7 +2820,7 @@ static int __init report_memory(void)
 
        return 0;
 }
-device_initcall(report_memory);
+arch_initcall(report_memory);
 
 #ifdef CONFIG_SMP
 #define do_flush_tlb_kernel_range      smp_flush_tlb_kernel_range
index 7083c16..bb13763 100644 (file)
 static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
                LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
 
-struct kaslr_setup_data {
-       __u64 next;
-       __u32 type;
-       __u32 len;
-       __u8 data[1];
-} kaslr_setup_data;
-
 #define I8254_PORT_CONTROL     0x43
 #define I8254_PORT_COUNTER0    0x40
 #define I8254_CMD_READBACK     0xC0
@@ -302,29 +295,7 @@ static unsigned long find_random_addr(unsigned long minimum,
        return slots_fetch_random();
 }
 
-static void add_kaslr_setup_data(struct boot_params *params, __u8 enabled)
-{
-       struct setup_data *data;
-
-       kaslr_setup_data.type = SETUP_KASLR;
-       kaslr_setup_data.len = 1;
-       kaslr_setup_data.next = 0;
-       kaslr_setup_data.data[0] = enabled;
-
-       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
-
-       while (data && data->next)
-               data = (struct setup_data *)(unsigned long)data->next;
-
-       if (data)
-               data->next = (unsigned long)&kaslr_setup_data;
-       else
-               params->hdr.setup_data = (unsigned long)&kaslr_setup_data;
-
-}
-
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size)
@@ -335,17 +306,14 @@ unsigned char *choose_kernel_location(struct boot_params *params,
 #ifdef CONFIG_HIBERNATION
        if (!cmdline_find_option_bool("kaslr")) {
                debug_putstr("KASLR disabled by default...\n");
-               add_kaslr_setup_data(params, 0);
                goto out;
        }
 #else
        if (cmdline_find_option_bool("nokaslr")) {
                debug_putstr("KASLR disabled by cmdline...\n");
-               add_kaslr_setup_data(params, 0);
                goto out;
        }
 #endif
-       add_kaslr_setup_data(params, 1);
 
        /* Record the various known unsafe memory ranges. */
        mem_avoid_init((unsigned long)input, input_size,
index 5903089..a950864 100644 (file)
@@ -401,8 +401,7 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
         * the entire decompressed kernel plus relocation table, or the
         * entire decompressed kernel plus .bss and .brk sections.
         */
-       output = choose_kernel_location(real_mode, input_data, input_len,
-                                       output,
+       output = choose_kernel_location(input_data, input_len, output,
                                        output_len > run_size ? output_len
                                                              : run_size);
 
index ee3576b..04477d6 100644 (file)
@@ -57,8 +57,7 @@ int cmdline_find_option_bool(const char *option);
 
 #if CONFIG_RANDOMIZE_BASE
 /* aslr.c */
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size);
@@ -66,8 +65,7 @@ unsigned char *choose_kernel_location(struct boot_params *params,
 bool has_cpuflag(int flag);
 #else
 static inline
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size)
index 947c6bf..54f60ab 100644 (file)
@@ -1155,7 +1155,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
                src = kmalloc(req->cryptlen + req->assoclen, GFP_ATOMIC);
                if (!src)
                        return -ENOMEM;
-               assoc = (src + req->cryptlen + auth_tag_len);
+               assoc = (src + req->cryptlen);
                scatterwalk_map_and_copy(src, req->src, 0, req->cryptlen, 0);
                scatterwalk_map_and_copy(assoc, req->assoc, 0,
                        req->assoclen, 0);
@@ -1180,7 +1180,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
                scatterwalk_done(&src_sg_walk, 0, 0);
                scatterwalk_done(&assoc_sg_walk, 0, 0);
        } else {
-               scatterwalk_map_and_copy(dst, req->dst, 0, req->cryptlen, 1);
+               scatterwalk_map_and_copy(dst, req->dst, 0, tempCipherLen, 1);
                kfree(src);
        }
        return retval;
index 0dbc082..72ba21a 100644 (file)
@@ -370,7 +370,7 @@ static inline void drop_fpu(struct task_struct *tsk)
        preempt_disable();
        tsk->thread.fpu_counter = 0;
        __drop_fpu(tsk);
-       clear_used_math();
+       clear_stopped_child_used_math(tsk);
        preempt_enable();
 }
 
index 95e11f7..f97fbe3 100644 (file)
@@ -51,8 +51,6 @@ extern int devmem_is_allowed(unsigned long pagenr);
 extern unsigned long max_low_pfn_mapped;
 extern unsigned long max_pfn_mapped;
 
-extern bool kaslr_enabled;
-
 static inline phys_addr_t get_max_mapped(void)
 {
        return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT;
index fa1195d..164e3f8 100644 (file)
@@ -93,6 +93,8 @@ extern raw_spinlock_t pci_config_lock;
 extern int (*pcibios_enable_irq)(struct pci_dev *dev);
 extern void (*pcibios_disable_irq)(struct pci_dev *dev);
 
+extern bool mp_should_keep_irq(struct device *dev);
+
 struct pci_raw_ops {
        int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
                                                int reg, int len, u32 *val);
index 44e6dd7..225b098 100644 (file)
@@ -7,7 +7,6 @@
 #define SETUP_DTB                      2
 #define SETUP_PCI                      3
 #define SETUP_EFI                      4
-#define SETUP_KASLR                    5
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK       0x07FF
index 3d525c6..803b684 100644 (file)
@@ -1338,6 +1338,26 @@ static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
 }
 
 /*
+ * ACPI offers an alternative platform interface model that removes
+ * ACPI hardware requirements for platforms that do not implement
+ * the PC Architecture.
+ *
+ * We initialize the Hardware-reduced ACPI model here:
+ */
+static void __init acpi_reduced_hw_init(void)
+{
+       if (acpi_gbl_reduced_hardware) {
+               /*
+                * Override x86_init functions and bypass legacy pic
+                * in Hardware-reduced ACPI mode
+                */
+               x86_init.timers.timer_init      = x86_init_noop;
+               x86_init.irqs.pre_vector_init   = x86_init_noop;
+               legacy_pic                      = &null_legacy_pic;
+       }
+}
+
+/*
  * If your system is blacklisted here, but you find that acpi=force
  * works for you, please contact linux-acpi@vger.kernel.org
  */
@@ -1536,6 +1556,11 @@ int __init early_acpi_boot_init(void)
         */
        early_acpi_process_madt();
 
+       /*
+        * Hardware-reduced ACPI mode initialization:
+        */
+       acpi_reduced_hw_init();
+
        return 0;
 }
 
index c2fd21f..017149c 100644 (file)
@@ -37,10 +37,12 @@ static const struct apic apic_numachip;
 static unsigned int get_apic_id(unsigned long x)
 {
        unsigned long value;
-       unsigned int id;
+       unsigned int id = (x >> 24) & 0xff;
 
-       rdmsrl(MSR_FAM10H_NODE_ID, value);
-       id = ((x >> 24) & 0xffU) | ((value << 2) & 0xff00U);
+       if (static_cpu_has_safe(X86_FEATURE_NODEID_MSR)) {
+               rdmsrl(MSR_FAM10H_NODE_ID, value);
+               id |= (value << 2) & 0xff00;
+       }
 
        return id;
 }
@@ -155,10 +157,18 @@ static int __init numachip_probe(void)
 
 static void fixup_cpu_id(struct cpuinfo_x86 *c, int node)
 {
-       if (c->phys_proc_id != node) {
-               c->phys_proc_id = node;
-               per_cpu(cpu_llc_id, smp_processor_id()) = node;
+       u64 val;
+       u32 nodes = 1;
+
+       this_cpu_write(cpu_llc_id, node);
+
+       /* Account for nodes per socket in multi-core-module processors */
+       if (static_cpu_has_safe(X86_FEATURE_NODEID_MSR)) {
+               rdmsrl(MSR_FAM10H_NODE_ID, val);
+               nodes = ((val >> 3) & 7) + 1;
        }
+
+       c->phys_proc_id = node / nodes;
 }
 
 static int __init numachip_system_init(void)
index 498b6d9..2589906 100644 (file)
@@ -212,11 +212,11 @@ static struct event_constraint intel_hsw_event_constraints[] = {
        INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
        INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
        /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
-       INTEL_EVENT_CONSTRAINT(0x08a3, 0x4),
+       INTEL_UEVENT_CONSTRAINT(0x08a3, 0x4),
        /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */
-       INTEL_EVENT_CONSTRAINT(0x0ca3, 0x4),
+       INTEL_UEVENT_CONSTRAINT(0x0ca3, 0x4),
        /* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */
-       INTEL_EVENT_CONSTRAINT(0x04a3, 0xf),
+       INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf),
        EVENT_CONSTRAINT_END
 };
 
@@ -1649,11 +1649,11 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event
        if (c)
                return c;
 
-       c = intel_pebs_constraints(event);
+       c = intel_shared_regs_constraints(cpuc, event);
        if (c)
                return c;
 
-       c = intel_shared_regs_constraints(cpuc, event);
+       c = intel_pebs_constraints(event);
        if (c)
                return c;
 
index 1d74d16..f0095a7 100644 (file)
@@ -364,12 +364,21 @@ system_call_fastpath:
  * Has incomplete stack frame and undefined top of stack.
  */
 ret_from_sys_call:
-       testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
-       jnz int_ret_from_sys_call_fixup /* Go the the slow path */
-
        LOCKDEP_SYS_EXIT
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
+
+       /*
+        * We must check ti flags with interrupts (or at least preemption)
+        * off because we must *never* return to userspace without
+        * processing exit work that is enqueued if we're preempted here.
+        * In particular, returning to userspace with any of the one-shot
+        * flags (TIF_NOTIFY_RESUME, TIF_USER_RETURN_NOTIFY, etc) set is
+        * very bad.
+        */
+       testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
+       jnz int_ret_from_sys_call_fixup /* Go the the slow path */
+
        CFI_REMEMBER_STATE
        /*
         * sysretq will re-enable interrupts:
@@ -386,7 +395,7 @@ ret_from_sys_call:
 
 int_ret_from_sys_call_fixup:
        FIXUP_TOP_OF_STACK %r11, -ARGOFFSET
-       jmp int_ret_from_sys_call
+       jmp int_ret_from_sys_call_irqs_off
 
        /* Do syscall tracing */
 tracesys:
@@ -432,6 +441,7 @@ tracesys_phase2:
 GLOBAL(int_ret_from_sys_call)
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
+int_ret_from_sys_call_irqs_off:
        movl $_TIF_ALLWORK_MASK,%edi
        /* edi: mask to check */
 GLOBAL(int_with_check)
@@ -789,7 +799,21 @@ retint_swapgs:             /* return to user-space */
        cmpq %r11,(EFLAGS-ARGOFFSET)(%rsp)      /* R11 == RFLAGS */
        jne opportunistic_sysret_failed
 
-       testq $X86_EFLAGS_RF,%r11               /* sysret can't restore RF */
+       /*
+        * SYSRET can't restore RF.  SYSRET can restore TF, but unlike IRET,
+        * restoring TF results in a trap from userspace immediately after
+        * SYSRET.  This would cause an infinite loop whenever #DB happens
+        * with register state that satisfies the opportunistic SYSRET
+        * conditions.  For example, single-stepping this user code:
+        *
+        *           movq $stuck_here,%rcx
+        *           pushfq
+        *           popq %r11
+        *   stuck_here:
+        *
+        * would never get past 'stuck_here'.
+        */
+       testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11
        jnz opportunistic_sysret_failed
 
        /* nothing to check for RSP */
index 7ec1d5f..25ecd56 100644 (file)
@@ -72,7 +72,7 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
        { "bx", 8, offsetof(struct pt_regs, bx) },
        { "cx", 8, offsetof(struct pt_regs, cx) },
        { "dx", 8, offsetof(struct pt_regs, dx) },
-       { "si", 8, offsetof(struct pt_regs, dx) },
+       { "si", 8, offsetof(struct pt_regs, si) },
        { "di", 8, offsetof(struct pt_regs, di) },
        { "bp", 8, offsetof(struct pt_regs, bp) },
        { "sp", 8, offsetof(struct pt_regs, sp) },
index 9bbb9b3..d1ac80b 100644 (file)
@@ -47,13 +47,21 @@ do {                                                        \
 
 #ifdef CONFIG_RANDOMIZE_BASE
 static unsigned long module_load_offset;
+static int randomize_modules = 1;
 
 /* Mutex protects the module_load_offset. */
 static DEFINE_MUTEX(module_kaslr_mutex);
 
+static int __init parse_nokaslr(char *p)
+{
+       randomize_modules = 0;
+       return 0;
+}
+early_param("nokaslr", parse_nokaslr);
+
 static unsigned long int get_module_load_offset(void)
 {
-       if (kaslr_enabled) {
+       if (randomize_modules) {
                mutex_lock(&module_kaslr_mutex);
                /*
                 * Calculate the module_load_offset the first time this
index bae6c60..86db4bc 100644 (file)
@@ -183,6 +183,16 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                },
        },
 
+       /* ASRock */
+       {       /* Handle problems with rebooting on ASRock Q1900DC-ITX */
+               .callback = set_pci_reboot,
+               .ident = "ASRock Q1900DC-ITX",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASRock"),
+                       DMI_MATCH(DMI_BOARD_NAME, "Q1900DC-ITX"),
+               },
+       },
+
        /* ASUS */
        {       /* Handle problems with rebooting on ASUS P4S800 */
                .callback = set_bios_reboot,
index 98dc931..0a2421c 100644 (file)
 unsigned long max_low_pfn_mapped;
 unsigned long max_pfn_mapped;
 
-bool __read_mostly kaslr_enabled = false;
-
 #ifdef CONFIG_DMI
 RESERVE_BRK(dmi_alloc, 65536);
 #endif
@@ -427,11 +425,6 @@ static void __init reserve_initrd(void)
 }
 #endif /* CONFIG_BLK_DEV_INITRD */
 
-static void __init parse_kaslr_setup(u64 pa_data, u32 data_len)
-{
-       kaslr_enabled = (bool)(pa_data + sizeof(struct setup_data));
-}
-
 static void __init parse_setup_data(void)
 {
        struct setup_data *data;
@@ -457,9 +450,6 @@ static void __init parse_setup_data(void)
                case SETUP_EFI:
                        parse_efi_setup(pa_data, data_len);
                        break;
-               case SETUP_KASLR:
-                       parse_kaslr_setup(pa_data, data_len);
-                       break;
                default:
                        break;
                }
@@ -842,14 +832,10 @@ static void __init trim_low_memory_range(void)
 static int
 dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
 {
-       if (kaslr_enabled)
-               pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n",
-                        (unsigned long)&_text - __START_KERNEL,
-                        __START_KERNEL,
-                        __START_KERNEL_map,
-                        MODULES_VADDR-1);
-       else
-               pr_emerg("Kernel Offset: disabled\n");
+       pr_emerg("Kernel Offset: 0x%lx from 0x%lx "
+                "(relocation range: 0x%lx-0x%lx)\n",
+                (unsigned long)&_text - __START_KERNEL, __START_KERNEL,
+                __START_KERNEL_map, MODULES_VADDR-1);
 
        return 0;
 }
index 9d2073e..4ff5d16 100644 (file)
@@ -384,7 +384,7 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
                goto exit;
        conditional_sti(regs);
 
-       if (!user_mode(regs))
+       if (!user_mode_vm(regs))
                die("bounds", regs, error_code);
 
        if (!cpu_feature_enabled(X86_FEATURE_MPX)) {
@@ -637,7 +637,7 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code)
         * then it's very likely the result of an icebp/int01 trap.
         * User wants a sigtrap for that.
         */
-       if (!dr6 && user_mode(regs))
+       if (!dr6 && user_mode_vm(regs))
                user_icebp = 1;
 
        /* Catch kmemcheck conditions first of all! */
index 34f66e5..cdc6cf9 100644 (file)
@@ -379,7 +379,7 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
                 * thread's fpu state, reconstruct fxstate from the fsave
                 * header. Sanitize the copied state etc.
                 */
-               struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
+               struct fpu *fpu = &tsk->thread.fpu;
                struct user_i387_ia32_struct env;
                int err = 0;
 
@@ -393,14 +393,15 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
                 */
                drop_fpu(tsk);
 
-               if (__copy_from_user(xsave, buf_fx, state_size) ||
+               if (__copy_from_user(&fpu->state->xsave, buf_fx, state_size) ||
                    __copy_from_user(&env, buf, sizeof(env))) {
+                       fpu_finit(fpu);
                        err = -1;
                } else {
                        sanitize_restored_xstate(tsk, &env, xstate_bv, fx_only);
-                       set_used_math();
                }
 
+               set_used_math();
                if (use_eager_fpu()) {
                        preempt_disable();
                        math_state_restore();
index cc31f7c..9541ba3 100644 (file)
@@ -507,6 +507,7 @@ static int picdev_read(struct kvm_pic *s,
                return -EOPNOTSUPP;
 
        if (len != 1) {
+               memset(val, 0, len);
                pr_pic_unimpl("non byte read\n");
                return 0;
        }
index b1947e0..46d4449 100644 (file)
@@ -422,6 +422,7 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
                        struct kvm_ioapic *ioapic, int vector, int trigger_mode)
 {
        int i;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
        for (i = 0; i < IOAPIC_NUM_PINS; i++) {
                union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
@@ -443,7 +444,8 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
                kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
                spin_lock(&ioapic->lock);
 
-               if (trigger_mode != IOAPIC_LEVEL_TRIG)
+               if (trigger_mode != IOAPIC_LEVEL_TRIG ||
+                   kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
                        continue;
 
                ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
index bd4e34d..4ee827d 100644 (file)
@@ -833,8 +833,7 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
 
 static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
 {
-       if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
-           kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
+       if (kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
                int trigger_mode;
                if (apic_test_vector(vector, apic->regs + APIC_TMR))
                        trigger_mode = IOAPIC_LEVEL_TRIG;
index f7b20b4..ae4f6d3 100644 (file)
@@ -2168,7 +2168,10 @@ static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
 {
        unsigned long *msr_bitmap;
 
-       if (irqchip_in_kernel(vcpu->kvm) && apic_x2apic_mode(vcpu->arch.apic)) {
+       if (is_guest_mode(vcpu))
+               msr_bitmap = vmx_msr_bitmap_nested;
+       else if (irqchip_in_kernel(vcpu->kvm) &&
+               apic_x2apic_mode(vcpu->arch.apic)) {
                if (is_long_mode(vcpu))
                        msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
                else
@@ -2476,8 +2479,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
        if (enable_ept) {
                /* nested EPT: emulate EPT also to L1 */
                vmx->nested.nested_vmx_secondary_ctls_high |=
-                       SECONDARY_EXEC_ENABLE_EPT |
-                       SECONDARY_EXEC_UNRESTRICTED_GUEST;
+                       SECONDARY_EXEC_ENABLE_EPT;
                vmx->nested.nested_vmx_ept_caps = VMX_EPT_PAGE_WALK_4_BIT |
                         VMX_EPTP_WB_BIT | VMX_EPT_2MB_PAGE_BIT |
                         VMX_EPT_INVEPT_BIT;
@@ -2491,6 +2493,10 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
        } else
                vmx->nested.nested_vmx_ept_caps = 0;
 
+       if (enable_unrestricted_guest)
+               vmx->nested.nested_vmx_secondary_ctls_high |=
+                       SECONDARY_EXEC_UNRESTRICTED_GUEST;
+
        /* miscellaneous data */
        rdmsr(MSR_IA32_VMX_MISC,
                vmx->nested.nested_vmx_misc_low,
@@ -9218,9 +9224,9 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        }
 
        if (cpu_has_vmx_msr_bitmap() &&
-           exec_control & CPU_BASED_USE_MSR_BITMAPS &&
-           nested_vmx_merge_msr_bitmap(vcpu, vmcs12)) {
-               vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_nested));
+           exec_control & CPU_BASED_USE_MSR_BITMAPS) {
+               nested_vmx_merge_msr_bitmap(vcpu, vmcs12);
+               /* MSR_BITMAP will be set by following vmx_set_efer. */
        } else
                exec_control &= ~CPU_BASED_USE_MSR_BITMAPS;
 
index bd7a70b..32bf19e 100644 (file)
@@ -2744,7 +2744,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_USER_NMI:
        case KVM_CAP_REINJECT_CONTROL:
        case KVM_CAP_IRQ_INJECT_STATUS:
-       case KVM_CAP_IRQFD:
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_IOEVENTFD_NO_LENGTH:
        case KVM_CAP_PIT2:
index 3d2612b..2fb3847 100644 (file)
@@ -513,31 +513,6 @@ void __init pcibios_set_cache_line_size(void)
        }
 }
 
-/*
- * Some device drivers assume dev->irq won't change after calling
- * pci_disable_device(). So delay releasing of IRQ resource to driver
- * unbinding time. Otherwise it will break PM subsystem and drivers
- * like xen-pciback etc.
- */
-static int pci_irq_notifier(struct notifier_block *nb, unsigned long action,
-                           void *data)
-{
-       struct pci_dev *dev = to_pci_dev(data);
-
-       if (action != BUS_NOTIFY_UNBOUND_DRIVER)
-               return NOTIFY_DONE;
-
-       if (pcibios_disable_irq)
-               pcibios_disable_irq(dev);
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block pci_irq_nb = {
-       .notifier_call = pci_irq_notifier,
-       .priority = INT_MIN,
-};
-
 int __init pcibios_init(void)
 {
        if (!raw_pci_ops) {
@@ -550,9 +525,6 @@ int __init pcibios_init(void)
 
        if (pci_bf_sort >= pci_force_bf)
                pci_sort_breadthfirst();
-
-       bus_register_notifier(&pci_bus_type, &pci_irq_nb);
-
        return 0;
 }
 
@@ -711,6 +683,12 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return 0;
 }
 
+void pcibios_disable_device (struct pci_dev *dev)
+{
+       if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
+               pcibios_disable_irq(dev);
+}
+
 int pci_ext_cfg_avail(void)
 {
        if (raw_pci_ext_ops)
index efb8493..852aa4c 100644 (file)
@@ -234,10 +234,10 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
 
 static void intel_mid_pci_irq_disable(struct pci_dev *dev)
 {
-       if (dev->irq_managed && dev->irq > 0) {
+       if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed &&
+           dev->irq > 0) {
                mp_unmap_irq(dev->irq);
                dev->irq_managed = 0;
-               dev->irq = 0;
        }
 }
 
index e71b3db..5dc6ca5 100644 (file)
@@ -1256,9 +1256,22 @@ static int pirq_enable_irq(struct pci_dev *dev)
        return 0;
 }
 
+bool mp_should_keep_irq(struct device *dev)
+{
+       if (dev->power.is_prepared)
+               return true;
+#ifdef CONFIG_PM
+       if (dev->power.runtime_status == RPM_SUSPENDING)
+               return true;
+#endif
+
+       return false;
+}
+
 static void pirq_disable_irq(struct pci_dev *dev)
 {
-       if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) {
+       if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
+           dev->irq_managed && dev->irq) {
                mp_unmap_irq(dev->irq);
                dev->irq = 0;
                dev->irq_managed = 0;
index 31776d0..d7ec4e2 100644 (file)
@@ -17,6 +17,7 @@
        .text
        .globl __kernel_sigreturn
        .type __kernel_sigreturn,@function
+       nop /* this guy is needed for .LSTARTFDEDLSI1 below (watch for HACK) */
        ALIGN
 __kernel_sigreturn:
 .LSTART_sigreturn:
index 9f93af5..b47124d 100644 (file)
@@ -91,6 +91,12 @@ EXPORT_SYMBOL_GPL(xen_p2m_size);
 unsigned long xen_max_p2m_pfn __read_mostly;
 EXPORT_SYMBOL_GPL(xen_max_p2m_pfn);
 
+#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT
+#define P2M_LIMIT CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT
+#else
+#define P2M_LIMIT 0
+#endif
+
 static DEFINE_SPINLOCK(p2m_update_lock);
 
 static unsigned long *p2m_mid_missing_mfn;
@@ -385,9 +391,11 @@ static void __init xen_rebuild_p2m_list(unsigned long *p2m)
 void __init xen_vmalloc_p2m_tree(void)
 {
        static struct vm_struct vm;
+       unsigned long p2m_limit;
 
+       p2m_limit = (phys_addr_t)P2M_LIMIT * 1024 * 1024 * 1024 / PAGE_SIZE;
        vm.flags = VM_ALLOC;
-       vm.size = ALIGN(sizeof(unsigned long) * xen_max_p2m_pfn,
+       vm.size = ALIGN(sizeof(unsigned long) * max(xen_max_p2m_pfn, p2m_limit),
                        PMD_SIZE * PMDS_PER_MID_PAGE);
        vm_area_register_early(&vm, PMD_SIZE * PMDS_PER_MID_PAGE);
        pr_notice("p2m virtual area at %p, size is %lx\n", vm.addr, vm.size);
index fc1ff3b..fd3fee8 100644 (file)
@@ -592,7 +592,7 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
        if (q->queue_flags & (1 << QUEUE_FLAG_SG_GAPS)) {
                struct bio_vec *bprev;
 
-               bprev = &rq->biotail->bi_io_vec[bio->bi_vcnt - 1];
+               bprev = &rq->biotail->bi_io_vec[rq->biotail->bi_vcnt - 1];
                if (bvec_gap_to_prev(bprev, bio->bi_io_vec[0].bv_offset))
                        return false;
        }
index d53a764..be3290c 100644 (file)
@@ -278,9 +278,11 @@ static int bt_get(struct blk_mq_alloc_data *data,
                /*
                 * We're out of tags on this hardware queue, kick any
                 * pending IO submits before going to sleep waiting for
-                * some to complete.
+                * some to complete. Note that hctx can be NULL here for
+                * reserved tag allocation.
                 */
-               blk_mq_run_hw_queue(hctx, false);
+               if (hctx)
+                       blk_mq_run_hw_queue(hctx, false);
 
                /*
                 * Retry tag allocation after running the hardware queue,
index 4f4bea2..b7b8933 100644 (file)
@@ -1938,7 +1938,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
         */
        if (percpu_ref_init(&q->mq_usage_counter, blk_mq_usage_counter_release,
                            PERCPU_REF_INIT_ATOMIC, GFP_KERNEL))
-               goto err_map;
+               goto err_mq_usage;
 
        setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q);
        blk_queue_rq_timeout(q, 30000);
@@ -1981,7 +1981,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
        blk_mq_init_cpu_queues(q, set->nr_hw_queues);
 
        if (blk_mq_init_hw_queues(q, set))
-               goto err_hw;
+               goto err_mq_usage;
 
        mutex_lock(&all_q_mutex);
        list_add_tail(&q->all_q_node, &all_q_list);
@@ -1993,7 +1993,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
 
        return q;
 
-err_hw:
+err_mq_usage:
        blk_cleanup_queue(q);
 err_hctxs:
        kfree(map);
index 6ed2cbe..12600bf 100644 (file)
@@ -585,7 +585,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                                     b->physical_block_size);
 
        t->io_min = max(t->io_min, b->io_min);
-       t->io_opt = lcm(t->io_opt, b->io_opt);
+       t->io_opt = lcm_not_zero(t->io_opt, b->io_opt);
 
        t->cluster &= b->cluster;
        t->discard_zeroes_data &= b->discard_zeroes_data;
@@ -616,7 +616,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                    b->raid_partial_stripes_expensive);
 
        /* Find lowest common alignment_offset */
-       t->alignment_offset = lcm(t->alignment_offset, alignment)
+       t->alignment_offset = lcm_not_zero(t->alignment_offset, alignment)
                % max(t->physical_block_size, t->io_min);
 
        /* Verify that new alignment_offset is on a logical block boundary */
@@ -643,7 +643,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                                                      b->max_discard_sectors);
                t->discard_granularity = max(t->discard_granularity,
                                             b->discard_granularity);
-               t->discard_alignment = lcm(t->discard_alignment, alignment) %
+               t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) %
                        t->discard_granularity;
        }
 
index e7f718d..b1def41 100644 (file)
@@ -485,6 +485,14 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        if (!pin || !dev->irq_managed || dev->irq <= 0)
                return;
 
+       /* Keep IOAPIC pin configuration when suspending */
+       if (dev->dev.power.is_prepared)
+               return;
+#ifdef CONFIG_PM
+       if (dev->dev.power.runtime_status == RPM_SUSPENDING)
+               return;
+#endif
+
        entry = acpi_pci_irq_lookup(dev, pin);
        if (!entry)
                return;
@@ -505,6 +513,5 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        if (gsi >= 0) {
                acpi_unregister_gsi(gsi);
                dev->irq_managed = 0;
-               dev->irq = 0;
        }
 }
index 4c35f08..23dac3b 100644 (file)
@@ -4204,9 +4204,18 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "PIONEER DVD-RW  DVR-216D",   NULL,   ATA_HORKAGE_NOSETXFER },
 
        /* devices that don't properly handle queued TRIM commands */
-       { "Micron_M[56]*",              NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+       { "Micron_M500*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial_CT*M500*",           NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Micron_M5[15]0*",            "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial_CT*M550*",           "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial_CT*MX100*",          "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Samsung SSD 850 PRO*",       NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
-       { "Crucial_CT*SSD*",            NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
 
        /*
         * As defined, the DRAT (Deterministic Read After Trim) and RZAT
@@ -4226,6 +4235,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
         */
        { "INTEL*SSDSC2MH*",            NULL,   0, },
 
+       { "Micron*",                    NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial*",                   NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "INTEL*SSD*",                 NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "SSD*INTEL*",                 NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "Samsung*SSD*",               NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
@@ -4737,7 +4748,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag)
                return NULL;
 
        /* libsas case */
-       if (!ap->scsi_host) {
+       if (ap->flags & ATA_FLAG_SAS_HOST) {
                tag = ata_sas_allocate_tag(ap);
                if (tag < 0)
                        return NULL;
@@ -4776,7 +4787,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
        tag = qc->tag;
        if (likely(ata_tag_valid(tag))) {
                qc->tag = ATA_TAG_POISON;
-               if (!ap->scsi_host)
+               if (ap->flags & ATA_FLAG_SAS_HOST)
                        ata_sas_free_tag(tag, ap);
        }
 }
index beb8b27..a13587b 100644 (file)
@@ -243,4 +243,12 @@ extern struct regcache_ops regcache_rbtree_ops;
 extern struct regcache_ops regcache_lzo_ops;
 extern struct regcache_ops regcache_flat_ops;
 
+static inline const char *regmap_name(const struct regmap *map)
+{
+       if (map->dev)
+               return dev_name(map->dev);
+
+       return map->name;
+}
+
 #endif
index d453a2c..81751a4 100644 (file)
@@ -307,7 +307,7 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
        if (pos == 0) {
                memmove(blk + offset * map->cache_word_size,
                        blk, rbnode->blklen * map->cache_word_size);
-               bitmap_shift_right(present, present, offset, blklen);
+               bitmap_shift_left(present, present, offset, blklen);
        }
 
        /* update the rbnode block, its size and the base register */
index f373c35..87db989 100644 (file)
@@ -218,7 +218,7 @@ int regcache_read(struct regmap *map,
                ret = map->cache_ops->read(map, reg, value);
 
                if (ret == 0)
-                       trace_regmap_reg_read_cache(map->dev, reg, *value);
+                       trace_regmap_reg_read_cache(map, reg, *value);
 
                return ret;
        }
@@ -311,7 +311,7 @@ int regcache_sync(struct regmap *map)
        dev_dbg(map->dev, "Syncing %s cache\n",
                map->cache_ops->name);
        name = map->cache_ops->name;
-       trace_regcache_sync(map->dev, name, "start");
+       trace_regcache_sync(map, name, "start");
 
        if (!map->cache_dirty)
                goto out;
@@ -346,7 +346,7 @@ out:
 
        regmap_async_complete(map);
 
-       trace_regcache_sync(map->dev, name, "stop");
+       trace_regcache_sync(map, name, "stop");
 
        return ret;
 }
@@ -381,7 +381,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
        name = map->cache_ops->name;
        dev_dbg(map->dev, "Syncing %s cache from %d-%d\n", name, min, max);
 
-       trace_regcache_sync(map->dev, name, "start region");
+       trace_regcache_sync(map, name, "start region");
 
        if (!map->cache_dirty)
                goto out;
@@ -401,7 +401,7 @@ out:
 
        regmap_async_complete(map);
 
-       trace_regcache_sync(map->dev, name, "stop region");
+       trace_regcache_sync(map, name, "stop region");
 
        return ret;
 }
@@ -428,7 +428,7 @@ int regcache_drop_region(struct regmap *map, unsigned int min,
 
        map->lock(map->lock_arg);
 
-       trace_regcache_drop_region(map->dev, min, max);
+       trace_regcache_drop_region(map, min, max);
 
        ret = map->cache_ops->drop(map, min, max);
 
@@ -455,7 +455,7 @@ void regcache_cache_only(struct regmap *map, bool enable)
        map->lock(map->lock_arg);
        WARN_ON(map->cache_bypass && enable);
        map->cache_only = enable;
-       trace_regmap_cache_only(map->dev, enable);
+       trace_regmap_cache_only(map, enable);
        map->unlock(map->lock_arg);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -493,7 +493,7 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
        map->lock(map->lock_arg);
        WARN_ON(map->cache_only && enable);
        map->cache_bypass = enable;
-       trace_regmap_cache_bypass(map->dev, enable);
+       trace_regmap_cache_bypass(map, enable);
        map->unlock(map->lock_arg);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_bypass);
@@ -608,7 +608,8 @@ static int regcache_sync_block_single(struct regmap *map, void *block,
        for (i = start; i < end; i++) {
                regtmp = block_base + (i * map->reg_stride);
 
-               if (!regcache_reg_present(cache_present, i))
+               if (!regcache_reg_present(cache_present, i) ||
+                   !regmap_writeable(map, regtmp))
                        continue;
 
                val = regcache_get_val(map, block, i);
@@ -677,7 +678,8 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
        for (i = start; i < end; i++) {
                regtmp = block_base + (i * map->reg_stride);
 
-               if (!regcache_reg_present(cache_present, i)) {
+               if (!regcache_reg_present(cache_present, i) ||
+                   !regmap_writeable(map, regtmp)) {
                        ret = regcache_sync_block_raw_flush(map, &data,
                                                            base, regtmp);
                        if (ret != 0)
index 6299a50..a6c3f75 100644 (file)
@@ -499,7 +499,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                goto err_alloc;
        }
 
-       ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags,
+       ret = request_threaded_irq(irq, NULL, regmap_irq_thread,
+                                  irq_flags | IRQF_ONESHOT,
                                   chip->name, d);
        if (ret != 0) {
                dev_err(map->dev, "Failed to request IRQ %d for %s: %d\n",
index f99b098..dbfe6a6 100644 (file)
@@ -1281,7 +1281,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
        if (map->async && map->bus->async_write) {
                struct regmap_async *async;
 
-               trace_regmap_async_write_start(map->dev, reg, val_len);
+               trace_regmap_async_write_start(map, reg, val_len);
 
                spin_lock_irqsave(&map->async_lock, flags);
                async = list_first_entry_or_null(&map->async_free,
@@ -1339,8 +1339,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
                return ret;
        }
 
-       trace_regmap_hw_write_start(map->dev, reg,
-                                   val_len / map->format.val_bytes);
+       trace_regmap_hw_write_start(map, reg, val_len / map->format.val_bytes);
 
        /* If we're doing a single register write we can probably just
         * send the work_buf directly, otherwise try to do a gather
@@ -1372,8 +1371,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
                kfree(buf);
        }
 
-       trace_regmap_hw_write_done(map->dev, reg,
-                                  val_len / map->format.val_bytes);
+       trace_regmap_hw_write_done(map, reg, val_len / map->format.val_bytes);
 
        return ret;
 }
@@ -1407,12 +1405,12 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
 
        map->format.format_write(map, reg, val);
 
-       trace_regmap_hw_write_start(map->dev, reg, 1);
+       trace_regmap_hw_write_start(map, reg, 1);
 
        ret = map->bus->write(map->bus_context, map->work_buf,
                              map->format.buf_size);
 
-       trace_regmap_hw_write_done(map->dev, reg, 1);
+       trace_regmap_hw_write_done(map, reg, 1);
 
        return ret;
 }
@@ -1470,7 +1468,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
                dev_info(map->dev, "%x <= %x\n", reg, val);
 #endif
 
-       trace_regmap_reg_write(map->dev, reg, val);
+       trace_regmap_reg_write(map, reg, val);
 
        return map->reg_write(context, reg, val);
 }
@@ -1773,7 +1771,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
        for (i = 0; i < num_regs; i++) {
                int reg = regs[i].reg;
                int val = regs[i].def;
-               trace_regmap_hw_write_start(map->dev, reg, 1);
+               trace_regmap_hw_write_start(map, reg, 1);
                map->format.format_reg(u8, reg, map->reg_shift);
                u8 += reg_bytes + pad_bytes;
                map->format.format_val(u8, val, 0);
@@ -1788,7 +1786,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
 
        for (i = 0; i < num_regs; i++) {
                int reg = regs[i].reg;
-               trace_regmap_hw_write_done(map->dev, reg, 1);
+               trace_regmap_hw_write_done(map, reg, 1);
        }
        return ret;
 }
@@ -2059,15 +2057,13 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
         */
        u8[0] |= map->read_flag_mask;
 
-       trace_regmap_hw_read_start(map->dev, reg,
-                                  val_len / map->format.val_bytes);
+       trace_regmap_hw_read_start(map, reg, val_len / map->format.val_bytes);
 
        ret = map->bus->read(map->bus_context, map->work_buf,
                             map->format.reg_bytes + map->format.pad_bytes,
                             val, val_len);
 
-       trace_regmap_hw_read_done(map->dev, reg,
-                                 val_len / map->format.val_bytes);
+       trace_regmap_hw_read_done(map, reg, val_len / map->format.val_bytes);
 
        return ret;
 }
@@ -2123,7 +2119,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
                        dev_info(map->dev, "%x => %x\n", reg, *val);
 #endif
 
-               trace_regmap_reg_read(map->dev, reg, *val);
+               trace_regmap_reg_read(map, reg, *val);
 
                if (!map->cache_bypass)
                        regcache_write(map, reg, *val);
@@ -2480,7 +2476,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
        struct regmap *map = async->map;
        bool wake;
 
-       trace_regmap_async_io_complete(map->dev);
+       trace_regmap_async_io_complete(map);
 
        spin_lock(&map->async_lock);
        list_move(&async->list, &map->async_free);
@@ -2525,7 +2521,7 @@ int regmap_async_complete(struct regmap *map)
        if (!map->bus || !map->bus->async_write)
                return 0;
 
-       trace_regmap_async_complete_start(map->dev);
+       trace_regmap_async_complete_start(map);
 
        wait_event(map->async_waitq, regmap_async_is_done(map));
 
@@ -2534,7 +2530,7 @@ int regmap_async_complete(struct regmap *map)
        map->async_ret = 0;
        spin_unlock_irqrestore(&map->async_lock, flags);
 
-       trace_regmap_async_complete_done(map->dev);
+       trace_regmap_async_complete_done(map);
 
        return ret;
 }
index 4bc2a5c..a98c41f 100644 (file)
@@ -803,10 +803,6 @@ static int __init nbd_init(void)
                return -EINVAL;
        }
 
-       nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
-       if (!nbd_dev)
-               return -ENOMEM;
-
        part_shift = 0;
        if (max_part > 0) {
                part_shift = fls(max_part);
@@ -828,6 +824,10 @@ static int __init nbd_init(void)
        if (nbds_max > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
 
+       nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
+       if (!nbd_dev)
+               return -ENOMEM;
+
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = alloc_disk(1 << part_shift);
                if (!disk)
index ceb32dd..e23be20 100644 (file)
@@ -3003,6 +3003,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        }
        get_device(dev->device);
 
+       INIT_LIST_HEAD(&dev->node);
        INIT_WORK(&dev->probe_work, nvme_async_probe);
        schedule_work(&dev->probe_work);
        return 0;
index fae2dbb..72d7028 100644 (file)
@@ -142,6 +142,7 @@ struct ports_device {
         * notification
         */
        struct work_struct control_work;
+       struct work_struct config_work;
 
        struct list_head ports;
 
@@ -1837,10 +1838,21 @@ static void config_intr(struct virtio_device *vdev)
 
        portdev = vdev->priv;
 
+       if (!use_multiport(portdev))
+               schedule_work(&portdev->config_work);
+}
+
+static void config_work_handler(struct work_struct *work)
+{
+       struct ports_device *portdev;
+
+       portdev = container_of(work, struct ports_device, control_work);
        if (!use_multiport(portdev)) {
+               struct virtio_device *vdev;
                struct port *port;
                u16 rows, cols;
 
+               vdev = portdev->vdev;
                virtio_cread(vdev, struct virtio_console_config, cols, &cols);
                virtio_cread(vdev, struct virtio_console_config, rows, &rows);
 
@@ -2040,12 +2052,14 @@ static int virtcons_probe(struct virtio_device *vdev)
 
        virtio_device_ready(portdev->vdev);
 
+       INIT_WORK(&portdev->config_work, &config_work_handler);
+       INIT_WORK(&portdev->control_work, &control_work_handler);
+
        if (multiport) {
                unsigned int nr_added_bufs;
 
                spin_lock_init(&portdev->c_ivq_lock);
                spin_lock_init(&portdev->c_ovq_lock);
-               INIT_WORK(&portdev->control_work, &control_work_handler);
 
                nr_added_bufs = fill_queue(portdev->c_ivq,
                                           &portdev->c_ivq_lock);
@@ -2113,6 +2127,8 @@ static void virtcons_remove(struct virtio_device *vdev)
        /* Finish up work that's lined up */
        if (use_multiport(portdev))
                cancel_work_sync(&portdev->control_work);
+       else
+               cancel_work_sync(&portdev->config_work);
 
        list_for_each_entry_safe(port, port2, &portdev->ports, list)
                unplug_port(port);
@@ -2164,6 +2180,7 @@ static int virtcons_freeze(struct virtio_device *vdev)
 
        virtqueue_disable_cb(portdev->c_ivq);
        cancel_work_sync(&portdev->control_work);
+       cancel_work_sync(&portdev->config_work);
        /*
         * Once more: if control_work_handler() was running, it would
         * enable the cb as the last step.
index 68161f7..a0b036c 100644 (file)
@@ -192,6 +192,7 @@ config SYS_SUPPORTS_EM_STI
 config SH_TIMER_CMT
        bool "Renesas CMT timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_CMT
        help
          This enables build of a clocksource and clockevent driver for
@@ -201,6 +202,7 @@ config SH_TIMER_CMT
 config SH_TIMER_MTU2
        bool "Renesas MTU2 timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_MTU2
        help
          This enables build of a clockevent driver for the Multi-Function
@@ -210,6 +212,7 @@ config SH_TIMER_MTU2
 config SH_TIMER_TMU
        bool "Renesas TMU timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_TMU
        help
          This enables build of a clocksource and clockevent driver for
index bba62f9..ec57ba2 100644 (file)
@@ -225,12 +225,12 @@ static int __init efm32_clockevent_init(struct device_node *np)
        clock_event_ddata.base = base;
        clock_event_ddata.periodic_top = DIV_ROUND_CLOSEST(rate, 1024 * HZ);
 
-       setup_irq(irq, &efm32_clock_event_irq);
-
        clockevents_config_and_register(&clock_event_ddata.evtdev,
                                        DIV_ROUND_CLOSEST(rate, 1024),
                                        0xf, 0xffff);
 
+       setup_irq(irq, &efm32_clock_event_irq);
+
        return 0;
 
 err_get_irq:
index 0226844..58597fb 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/irq.h>
 #include <linux/irqreturn.h>
 #include <linux/reset.h>
-#include <linux/sched_clock.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -137,11 +136,6 @@ static struct irqaction sun5i_timer_irq = {
        .dev_id = &sun5i_clockevent,
 };
 
-static u64 sun5i_timer_sched_read(void)
-{
-       return ~readl(timer_base + TIMER_CNTVAL_LO_REG(1));
-}
-
 static void __init sun5i_timer_init(struct device_node *node)
 {
        struct reset_control *rstc;
@@ -172,16 +166,11 @@ static void __init sun5i_timer_init(struct device_node *node)
        writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
               timer_base + TIMER_CTL_REG(1));
 
-       sched_clock_register(sun5i_timer_sched_read, 32, rate);
        clocksource_mmio_init(timer_base + TIMER_CNTVAL_LO_REG(1), node->name,
                              rate, 340, 32, clocksource_mmio_readl_down);
 
        ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 
-       ret = setup_irq(irq, &sun5i_timer_irq);
-       if (ret)
-               pr_warn("failed to setup irq %d\n", irq);
-
        /* Enable timer0 interrupt */
        val = readl(timer_base + TIMER_IRQ_EN_REG);
        writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG);
@@ -191,6 +180,10 @@ static void __init sun5i_timer_init(struct device_node *node)
 
        clockevents_config_and_register(&sun5i_clockevent, rate,
                                        TIMER_SYNC_TICKS, 0xffffffff);
+
+       ret = setup_irq(irq, &sun5i_timer_irq);
+       if (ret)
+               pr_warn("failed to setup irq %d\n", irq);
 }
 CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer",
                       sun5i_timer_init);
index c3efa41..6f75e9d 100644 (file)
@@ -52,15 +52,6 @@ of_coresight_get_endpoint_device(struct device_node *endpoint)
                               endpoint, of_dev_node_match);
 }
 
-static struct device_node *of_get_coresight_endpoint(
-               const struct device_node *parent, struct device_node *prev)
-{
-       struct device_node *node = of_graph_get_next_endpoint(parent, prev);
-
-       of_node_put(prev);
-       return node;
-}
-
 static void of_coresight_get_ports(struct device_node *node,
                                   int *nr_inport, int *nr_outport)
 {
@@ -68,7 +59,7 @@ static void of_coresight_get_ports(struct device_node *node,
        int in = 0, out = 0;
 
        do {
-               ep = of_get_coresight_endpoint(node, ep);
+               ep = of_graph_get_next_endpoint(node, ep);
                if (!ep)
                        break;
 
@@ -140,7 +131,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
                /* Iterate through each port to discover topology */
                do {
                        /* Get a handle on a port */
-                       ep = of_get_coresight_endpoint(node, ep);
+                       ep = of_graph_get_next_endpoint(node, ep);
                        if (!ep)
                                break;
 
index 38e6861..980151f 100644 (file)
@@ -37,11 +37,11 @@ static int mvebu_v7_enter_idle(struct cpuidle_device *dev,
                deepidle = true;
 
        ret = mvebu_v7_cpu_suspend(deepidle);
+       cpu_pm_exit();
+
        if (ret)
                return ret;
 
-       cpu_pm_exit();
-
        return index;
 }
 
@@ -50,17 +50,17 @@ static struct cpuidle_driver armadaxp_idle_driver = {
        .states[0]              = ARM_CPUIDLE_WFI_STATE,
        .states[1]              = {
                .enter                  = mvebu_v7_enter_idle,
-               .exit_latency           = 10,
+               .exit_latency           = 100,
                .power_usage            = 50,
-               .target_residency       = 100,
+               .target_residency       = 1000,
                .name                   = "MV CPU IDLE",
                .desc                   = "CPU power down",
        },
        .states[2]              = {
                .enter                  = mvebu_v7_enter_idle,
-               .exit_latency           = 100,
+               .exit_latency           = 1000,
                .power_usage            = 5,
-               .target_residency       = 1000,
+               .target_residency       = 10000,
                .flags                  = MVEBU_V7_FLAG_DEEP_IDLE,
                .name                   = "MV CPU DEEP IDLE",
                .desc                   = "CPU and L2 Fabric power down",
index 4a5fd24..83aa55d 100644 (file)
 
 #define DRIVER_NAME    "pl08xdmac"
 
+#define PL80X_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)
+
 static struct amba_driver pl08x_amba_driver;
 struct pl08x_driver_data;
 
@@ -2070,6 +2076,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->memcpy.device_pause = pl08x_pause;
        pl08x->memcpy.device_resume = pl08x_resume;
        pl08x->memcpy.device_terminate_all = pl08x_terminate_all;
+       pl08x->memcpy.src_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->memcpy.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->memcpy.directions = BIT(DMA_MEM_TO_MEM);
+       pl08x->memcpy.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
        /* Initialize slave engine */
        dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
@@ -2086,6 +2096,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->slave.device_pause = pl08x_pause;
        pl08x->slave.device_resume = pl08x_resume;
        pl08x->slave.device_terminate_all = pl08x_terminate_all;
+       pl08x->slave.src_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->slave.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->slave.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       pl08x->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
        /* Get the platform data */
        pl08x->pd = dev_get_platdata(&adev->dev);
index 1e1a4c5..0b4fc6f 100644 (file)
@@ -238,93 +238,126 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
 }
 
 /*
- * atc_get_current_descriptors -
- * locate the descriptor which equal to physical address in DSCR
- * @atchan: the channel we want to start
- * @dscr_addr: physical descriptor address in DSCR
+ * atc_get_desc_by_cookie - get the descriptor of a cookie
+ * @atchan: the DMA channel
+ * @cookie: the cookie to get the descriptor for
  */
-static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan,
-                                                       u32 dscr_addr)
+static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
+                                               dma_cookie_t cookie)
 {
-       struct at_desc  *desc, *_desc, *child, *desc_cur = NULL;
+       struct at_desc *desc, *_desc;
 
-       list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
-               if (desc->lli.dscr == dscr_addr) {
-                       desc_cur = desc;
-                       break;
-               }
+       list_for_each_entry_safe(desc, _desc, &atchan->queue, desc_node) {
+               if (desc->txd.cookie == cookie)
+                       return desc;
+       }
 
-               list_for_each_entry(child, &desc->tx_list, desc_node) {
-                       if (child->lli.dscr == dscr_addr) {
-                               desc_cur = child;
-                               break;
-                       }
-               }
+       list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
+               if (desc->txd.cookie == cookie)
+                       return desc;
        }
 
-       return desc_cur;
+       return NULL;
 }
 
-/*
- * atc_get_bytes_left -
- * Get the number of bytes residue in dma buffer,
- * @chan: the channel we want to start
+/**
+ * atc_calc_bytes_left - calculates the number of bytes left according to the
+ * value read from CTRLA.
+ *
+ * @current_len: the number of bytes left before reading CTRLA
+ * @ctrla: the value of CTRLA
+ * @desc: the descriptor containing the transfer width
+ */
+static inline int atc_calc_bytes_left(int current_len, u32 ctrla,
+                                       struct at_desc *desc)
+{
+       return current_len - ((ctrla & ATC_BTSIZE_MAX) << desc->tx_width);
+}
+
+/**
+ * atc_calc_bytes_left_from_reg - calculates the number of bytes left according
+ * to the current value of CTRLA.
+ *
+ * @current_len: the number of bytes left before reading CTRLA
+ * @atchan: the channel to read CTRLA for
+ * @desc: the descriptor containing the transfer width
+ */
+static inline int atc_calc_bytes_left_from_reg(int current_len,
+                       struct at_dma_chan *atchan, struct at_desc *desc)
+{
+       u32 ctrla = channel_readl(atchan, CTRLA);
+
+       return atc_calc_bytes_left(current_len, ctrla, desc);
+}
+
+/**
+ * atc_get_bytes_left - get the number of bytes residue for a cookie
+ * @chan: DMA channel
+ * @cookie: transaction identifier to check status of
  */
-static int atc_get_bytes_left(struct dma_chan *chan)
+static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
 {
        struct at_dma_chan      *atchan = to_at_dma_chan(chan);
-       struct at_dma           *atdma = to_at_dma(chan->device);
-       int     chan_id = atchan->chan_common.chan_id;
        struct at_desc *desc_first = atc_first_active(atchan);
-       struct at_desc *desc_cur;
-       int ret = 0, count = 0;
+       struct at_desc *desc;
+       int ret;
+       u32 ctrla, dscr;
 
        /*
-        * Initialize necessary values in the first time.
-        * remain_desc record remain desc length.
+        * If the cookie doesn't match to the currently running transfer then
+        * we can return the total length of the associated DMA transfer,
+        * because it is still queued.
         */
-       if (atchan->remain_desc == 0)
-               /* First descriptor embedds the transaction length */
-               atchan->remain_desc = desc_first->len;
+       desc = atc_get_desc_by_cookie(atchan, cookie);
+       if (desc == NULL)
+               return -EINVAL;
+       else if (desc != desc_first)
+               return desc->total_len;
 
-       /*
-        * This happens when current descriptor transfer complete.
-        * The residual buffer size should reduce current descriptor length.
-        */
-       if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) {
-               clear_bit(ATC_IS_BTC, &atchan->status);
-               desc_cur = atc_get_current_descriptors(atchan,
-                                               channel_readl(atchan, DSCR));
-               if (!desc_cur) {
-                       ret = -EINVAL;
-                       goto out;
-               }
+       /* cookie matches to the currently running transfer */
+       ret = desc_first->total_len;
 
-               count = (desc_cur->lli.ctrla & ATC_BTSIZE_MAX)
-                       << desc_first->tx_width;
-               if (atchan->remain_desc < count) {
-                       ret = -EINVAL;
-                       goto out;
+       if (desc_first->lli.dscr) {
+               /* hardware linked list transfer */
+
+               /*
+                * Calculate the residue by removing the length of the child
+                * descriptors already transferred from the total length.
+                * To get the current child descriptor we can use the value of
+                * the channel's DSCR register and compare it against the value
+                * of the hardware linked list structure of each child
+                * descriptor.
+                */
+
+               ctrla = channel_readl(atchan, CTRLA);
+               rmb(); /* ensure CTRLA is read before DSCR */
+               dscr = channel_readl(atchan, DSCR);
+
+               /* for the first descriptor we can be more accurate */
+               if (desc_first->lli.dscr == dscr)
+                       return atc_calc_bytes_left(ret, ctrla, desc_first);
+
+               ret -= desc_first->len;
+               list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
+                       if (desc->lli.dscr == dscr)
+                               break;
+
+                       ret -= desc->len;
                }
 
-               atchan->remain_desc -= count;
-               ret = atchan->remain_desc;
-       } else {
                /*
-                * Get residual bytes when current
-                * descriptor transfer in progress.
+                * For the last descriptor in the chain we can calculate
+                * the remaining bytes using the channel's register.
+                * Note that the transfer width of the first and last
+                * descriptor may differ.
                 */
-               count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX)
-                               << (desc_first->tx_width);
-               ret = atchan->remain_desc - count;
+               if (!desc->lli.dscr)
+                       ret = atc_calc_bytes_left_from_reg(ret, atchan, desc);
+       } else {
+               /* single transfer */
+               ret = atc_calc_bytes_left_from_reg(ret, atchan, desc_first);
        }
-       /*
-        * Check fifo empty.
-        */
-       if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id)))
-               atc_issue_pending(chan);
 
-out:
        return ret;
 }
 
@@ -539,8 +572,6 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
                                        /* Give information to tasklet */
                                        set_bit(ATC_IS_ERROR, &atchan->status);
                                }
-                               if (pending & AT_DMA_BTC(i))
-                                       set_bit(ATC_IS_BTC, &atchan->status);
                                tasklet_schedule(&atchan->tasklet);
                                ret = IRQ_HANDLED;
                        }
@@ -653,14 +684,18 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                desc->lli.ctrlb = ctrlb;
 
                desc->txd.cookie = 0;
+               desc->len = xfer_count << src_width;
 
                atc_desc_chain(&first, &prev, desc);
        }
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = len;
+       first->total_len = len;
+
+       /* set transfer width for the calculation of the residue */
        first->tx_width = src_width;
+       prev->tx_width = src_width;
 
        /* set end-of-link to the last link descriptor of list*/
        set_desc_eol(desc);
@@ -752,6 +787,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                        | ATC_SRC_WIDTH(mem_width)
                                        | len >> mem_width;
                        desc->lli.ctrlb = ctrlb;
+                       desc->len = len;
 
                        atc_desc_chain(&first, &prev, desc);
                        total_len += len;
@@ -792,6 +828,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                        | ATC_DST_WIDTH(mem_width)
                                        | len >> reg_width;
                        desc->lli.ctrlb = ctrlb;
+                       desc->len = len;
 
                        atc_desc_chain(&first, &prev, desc);
                        total_len += len;
@@ -806,8 +843,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = total_len;
+       first->total_len = total_len;
+
+       /* set transfer width for the calculation of the residue */
        first->tx_width = reg_width;
+       prev->tx_width = reg_width;
 
        /* first link descriptor of list is responsible of flags */
        first->txd.flags = flags; /* client is in control of this ack */
@@ -872,6 +912,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
                                | ATC_FC_MEM2PER
                                | ATC_SIF(atchan->mem_if)
                                | ATC_DIF(atchan->per_if);
+               desc->len = period_len;
                break;
 
        case DMA_DEV_TO_MEM:
@@ -883,6 +924,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
                                | ATC_FC_PER2MEM
                                | ATC_SIF(atchan->per_if)
                                | ATC_DIF(atchan->mem_if);
+               desc->len = period_len;
                break;
 
        default:
@@ -964,7 +1006,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = buf_len;
+       first->total_len = buf_len;
        first->tx_width = reg_width;
 
        return &first->txd;
@@ -1118,7 +1160,7 @@ atc_tx_status(struct dma_chan *chan,
        spin_lock_irqsave(&atchan->lock, flags);
 
        /*  Get number of bytes left in the active transactions */
-       bytes = atc_get_bytes_left(chan);
+       bytes = atc_get_bytes_left(chan, cookie);
 
        spin_unlock_irqrestore(&atchan->lock, flags);
 
@@ -1214,7 +1256,6 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
 
        spin_lock_irqsave(&atchan->lock, flags);
        atchan->descs_allocated = i;
-       atchan->remain_desc = 0;
        list_splice(&tmp_list, &atchan->free_list);
        dma_cookie_init(chan);
        spin_unlock_irqrestore(&atchan->lock, flags);
@@ -1257,7 +1298,6 @@ static void atc_free_chan_resources(struct dma_chan *chan)
        list_splice_init(&atchan->free_list, &list);
        atchan->descs_allocated = 0;
        atchan->status = 0;
-       atchan->remain_desc = 0;
 
        dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
 }
index d6bba6c..2727ca5 100644 (file)
@@ -181,8 +181,9 @@ struct at_lli {
  * @at_lli: hardware lli structure
  * @txd: support for the async_tx api
  * @desc_node: node on the channed descriptors list
- * @len: total transaction bytecount
+ * @len: descriptor byte count
  * @tx_width: transfer width
+ * @total_len: total transaction byte count
  */
 struct at_desc {
        /* FIRST values the hardware uses */
@@ -194,6 +195,7 @@ struct at_desc {
        struct list_head                desc_node;
        size_t                          len;
        u32                             tx_width;
+       size_t                          total_len;
 };
 
 static inline struct at_desc *
@@ -213,7 +215,6 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
 enum atc_status {
        ATC_IS_ERROR = 0,
        ATC_IS_PAUSED = 1,
-       ATC_IS_BTC = 2,
        ATC_IS_CYCLIC = 24,
 };
 
@@ -231,7 +232,6 @@ enum atc_status {
  * @save_cfg: configuration register that is saved on suspend/resume cycle
  * @save_dscr: for cyclic operations, preserve next descriptor address in
  *             the cyclic list on suspend/resume cycle
- * @remain_desc: to save remain desc length
  * @dma_sconfig: configuration for slave transfers, passed via
  * .device_config
  * @lock: serializes enqueue/dequeue operations to descriptors lists
@@ -251,7 +251,6 @@ struct at_dma_chan {
        struct tasklet_struct   tasklet;
        u32                     save_cfg;
        u32                     save_dscr;
-       u32                     remain_desc;
        struct dma_slave_config dma_sconfig;
 
        spinlock_t              lock;
index 0723096..c92d6a7 100644 (file)
@@ -475,6 +475,7 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan)
         * c->desc is NULL and exit.)
         */
        if (c->desc) {
+               bcm2835_dma_desc_free(&c->desc->vd);
                c->desc = NULL;
                bcm2835_dma_abort(c->chan_base);
 
index 4527a3e..8488441 100644 (file)
@@ -511,6 +511,9 @@ static void jz4740_dma_desc_free(struct virt_dma_desc *vdesc)
        kfree(container_of(vdesc, struct jz4740_dma_desc, vdesc));
 }
 
+#define JZ4740_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
+
 static int jz4740_dma_probe(struct platform_device *pdev)
 {
        struct jz4740_dmaengine_chan *chan;
@@ -548,6 +551,10 @@ static int jz4740_dma_probe(struct platform_device *pdev)
        dd->device_prep_dma_cyclic = jz4740_dma_prep_dma_cyclic;
        dd->device_config = jz4740_dma_slave_config;
        dd->device_terminate_all = jz4740_dma_terminate_all;
+       dd->src_addr_widths = JZ4740_DMA_BUSWIDTHS;
+       dd->dst_addr_widths = JZ4740_DMA_BUSWIDTHS;
+       dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
        dd->dev = &pdev->dev;
        INIT_LIST_HEAD(&dd->channels);
 
index 6565a36..b2c3ae0 100644 (file)
@@ -26,6 +26,8 @@
 
 #include "internal.h"
 
+#define DRV_NAME       "dw_dmac"
+
 static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
                                        struct of_dma *ofdma)
 {
@@ -284,7 +286,7 @@ static struct platform_driver dw_driver = {
        .remove         = dw_remove,
        .shutdown       = dw_shutdown,
        .driver = {
-               .name   = "dw_dmac",
+               .name   = DRV_NAME,
                .pm     = &dw_dev_pm_ops,
                .of_match_table = of_match_ptr(dw_dma_of_id_table),
                .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
@@ -305,3 +307,4 @@ module_exit(dw_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
+MODULE_ALIAS("platform:" DRV_NAME);
index 276157f..53dbd3b 100644 (file)
@@ -260,6 +260,13 @@ static int edma_terminate_all(struct dma_chan *chan)
         */
        if (echan->edesc) {
                int cyclic = echan->edesc->cyclic;
+
+               /*
+                * free the running request descriptor
+                * since it is not in any of the vdesc lists
+                */
+               edma_desc_free(&echan->edesc->vdesc);
+
                echan->edesc = NULL;
                edma_stop(echan->ch_num);
                /* Move the cyclic channel back to default queue */
index 18c0a13..66a0efb 100644 (file)
@@ -531,6 +531,10 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
                dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
        }
 
+       /* Set bits of CONFIG register with dynamic context switching */
+       if (readl(sdma->regs + SDMA_H_CONFIG) == 0)
+               writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
+
        return ret ? 0 : -ETIMEDOUT;
 }
 
@@ -1394,9 +1398,6 @@ static int sdma_init(struct sdma_engine *sdma)
 
        writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
 
-       /* Set bits of CONFIG register with given context switching mode */
-       writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
-
        /* Initializes channel's priorities */
        sdma_set_channel_priority(&sdma->channel[0], 7);
 
index 15cab7d..b463410 100644 (file)
@@ -193,8 +193,10 @@ static int moxart_terminate_all(struct dma_chan *chan)
 
        spin_lock_irqsave(&ch->vc.lock, flags);
 
-       if (ch->desc)
+       if (ch->desc) {
+               moxart_dma_desc_free(&ch->desc->vd);
                ch->desc = NULL;
+       }
 
        ctrl = readl(ch->base + REG_OFF_CTRL);
        ctrl &= ~(APB_DMA_ENABLE | APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
index 7dd6dd1..167dbaf 100644 (file)
@@ -981,6 +981,7 @@ static int omap_dma_terminate_all(struct dma_chan *chan)
         * c->desc is NULL and exit.)
         */
        if (c->desc) {
+               omap_dma_desc_free(&c->desc->vd);
                c->desc = NULL;
                /* Avoid stopping the dma twice */
                if (!c->paused)
index 69fac06..2eebd28 100644 (file)
@@ -86,10 +86,13 @@ static void dmi_table(u8 *buf, u32 len, int num,
        int i = 0;
 
        /*
-        *      Stop when we see all the items the table claimed to have
-        *      OR we run off the end of the table (also happens)
+        * Stop when we have seen all the items the table claimed to have
+        * (SMBIOS < 3.0 only) OR we reach an end-of-table marker OR we run
+        * off the end of the table (should never happen but sometimes does
+        * on bogus implementations.)
         */
-       while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
+       while ((!num || i < num) &&
+              (data - buf + sizeof(struct dmi_header)) <= len) {
                const struct dmi_header *dm = (const struct dmi_header *)data;
 
                /*
@@ -529,21 +532,10 @@ static int __init dmi_smbios3_present(const u8 *buf)
        if (memcmp(buf, "_SM3_", 5) == 0 &&
            buf[6] < 32 && dmi_checksum(buf, buf[6])) {
                dmi_ver = get_unaligned_be16(buf + 7);
+               dmi_num = 0;                    /* No longer specified */
                dmi_len = get_unaligned_le32(buf + 12);
                dmi_base = get_unaligned_le64(buf + 16);
 
-               /*
-                * The 64-bit SMBIOS 3.0 entry point no longer has a field
-                * containing the number of structures present in the table.
-                * Instead, it defines the table size as a maximum size, and
-                * relies on the end-of-table structure type (#127) to be used
-                * to signal the end of the table.
-                * So let's define dmi_num as an upper bound as well: each
-                * structure has a 4 byte header, so dmi_len / 4 is an upper
-                * bound for the number of structures in the table.
-                */
-               dmi_num = dmi_len / 4;
-
                if (dmi_walk_early(dmi_decode) == 0) {
                        pr_info("SMBIOS %d.%d present.\n",
                                dmi_ver >> 8, dmi_ver & 0xFF);
index a6952ba..a65b751 100644 (file)
@@ -334,7 +334,7 @@ static struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
        .xlate  = irq_domain_xlate_twocell,
 };
 
-static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
+static struct of_device_id mpc8xxx_gpio_ids[] = {
        { .compatible = "fsl,mpc8349-gpio", },
        { .compatible = "fsl,mpc8572-gpio", },
        { .compatible = "fsl,mpc8610-gpio", },
index 257e298..045a952 100644 (file)
@@ -219,7 +219,7 @@ static int syscon_gpio_probe(struct platform_device *pdev)
                ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2,
                                                 &priv->dir_reg_offset);
                if (ret)
-                       dev_err(dev, "can't read the dir register offset!\n");
+                       dev_dbg(dev, "can't read the dir register offset!\n");
 
                priv->dir_reg_offset <<= 3;
        }
index c0929d9..df990f2 100644 (file)
@@ -201,6 +201,10 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
        if (!handler)
                return AE_BAD_PARAMETER;
 
+       pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
+       if (pin < 0)
+               return AE_BAD_PARAMETER;
+
        desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event");
        if (IS_ERR(desc)) {
                dev_err(chip->dev, "Failed to request GPIO\n");
@@ -551,6 +555,12 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
                struct gpio_desc *desc;
                bool found;
 
+               pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
+               if (pin < 0) {
+                       status = AE_BAD_PARAMETER;
+                       goto out;
+               }
+
                mutex_lock(&achip->conn_lock);
 
                found = false;
index 151a050..47f2ce8 100644 (file)
@@ -165,6 +165,15 @@ config DRM_SAVAGE
          Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
          chipset. If M is selected the module will be called savage.
 
+config DRM_VGEM
+       tristate "Virtual GEM provider"
+       depends on DRM
+       help
+         Choose this option to get a virtual graphics memory manager,
+         as used by Mesa's software renderer for enhanced performance.
+         If M is selected the module will be called vgem.
+
+
 source "drivers/gpu/drm/exynos/Kconfig"
 
 source "drivers/gpu/drm/rockchip/Kconfig"
index 2c239b9..7d4944e 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_DRM_SIS)   += sis/
 obj-$(CONFIG_DRM_SAVAGE)+= savage/
 obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
 obj-$(CONFIG_DRM_VIA)  +=via/
+obj-$(CONFIG_DRM_VGEM) += vgem/
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
 obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
index d717430..69af73f 100644 (file)
@@ -649,6 +649,7 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
        pr_debug("     sdma queue id: %d\n", q->properties.sdma_queue_id);
        pr_debug("     sdma engine id: %d\n", q->properties.sdma_engine_id);
 
+       init_sdma_vm(dqm, q, qpd);
        retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
                                &q->gart_mqd_addr, &q->properties);
        if (retval != 0) {
@@ -656,7 +657,14 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
                return retval;
        }
 
-       init_sdma_vm(dqm, q, qpd);
+       retval = mqd->load_mqd(mqd, q->mqd, 0,
+                               0, NULL);
+       if (retval != 0) {
+               deallocate_sdma_queue(dqm, q->sdma_id);
+               mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
+               return retval;
+       }
+
        return 0;
 }
 
index e415a2a..c7d298e 100644 (file)
@@ -44,7 +44,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
        BUG_ON(!kq || !dev);
        BUG_ON(type != KFD_QUEUE_TYPE_DIQ && type != KFD_QUEUE_TYPE_HIQ);
 
-       pr_debug("kfd: In func %s initializing queue type %d size %d\n",
+       pr_debug("amdkfd: In func %s initializing queue type %d size %d\n",
                        __func__, KFD_QUEUE_TYPE_HIQ, queue_size);
 
        nop.opcode = IT_NOP;
@@ -69,12 +69,16 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
 
        prop.doorbell_ptr = kfd_get_kernel_doorbell(dev, &prop.doorbell_off);
 
-       if (prop.doorbell_ptr == NULL)
+       if (prop.doorbell_ptr == NULL) {
+               pr_err("amdkfd: error init doorbell");
                goto err_get_kernel_doorbell;
+       }
 
        retval = kfd_gtt_sa_allocate(dev, queue_size, &kq->pq);
-       if (retval != 0)
+       if (retval != 0) {
+               pr_err("amdkfd: error init pq queues size (%d)\n", queue_size);
                goto err_pq_allocate_vidmem;
+       }
 
        kq->pq_kernel_addr = kq->pq->cpu_ptr;
        kq->pq_gpu_addr = kq->pq->gpu_addr;
@@ -165,10 +169,8 @@ err_rptr_allocate_vidmem:
 err_eop_allocate_vidmem:
        kfd_gtt_sa_free(dev, kq->pq);
 err_pq_allocate_vidmem:
-       pr_err("kfd: error init pq\n");
        kfd_release_kernel_doorbell(dev, prop.doorbell_ptr);
 err_get_kernel_doorbell:
-       pr_err("kfd: error init doorbell");
        return false;
 
 }
@@ -187,6 +189,8 @@ static void uninitialize(struct kernel_queue *kq)
        else if (kq->queue->properties.type == KFD_QUEUE_TYPE_DIQ)
                kfd_gtt_sa_free(kq->dev, kq->fence_mem_obj);
 
+       kq->mqd->uninit_mqd(kq->mqd, kq->queue->mqd, kq->queue->mqd_mem_obj);
+
        kfd_gtt_sa_free(kq->dev, kq->rptr_mem);
        kfd_gtt_sa_free(kq->dev, kq->wptr_mem);
        kq->ops_asic_specific.uninitialize(kq);
@@ -211,7 +215,7 @@ static int acquire_packet_buffer(struct kernel_queue *kq,
        queue_address = (unsigned int *)kq->pq_kernel_addr;
        queue_size_dwords = kq->queue->properties.queue_size / sizeof(uint32_t);
 
-       pr_debug("kfd: In func %s\nrptr: %d\nwptr: %d\nqueue_address 0x%p\n",
+       pr_debug("amdkfd: In func %s\nrptr: %d\nwptr: %d\nqueue_address 0x%p\n",
                        __func__, rptr, wptr, queue_address);
 
        available_size = (rptr - 1 - wptr + queue_size_dwords) %
@@ -296,7 +300,7 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
        }
 
        if (kq->ops.initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) {
-               pr_err("kfd: failed to init kernel queue\n");
+               pr_err("amdkfd: failed to init kernel queue\n");
                kfree(kq);
                return NULL;
        }
@@ -319,7 +323,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
 
        BUG_ON(!dev);
 
-       pr_err("kfd: starting kernel queue test\n");
+       pr_err("amdkfd: starting kernel queue test\n");
 
        kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ);
        BUG_ON(!kq);
@@ -330,7 +334,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
                buffer[i] = kq->nop_packet;
        kq->ops.submit_packet(kq);
 
-       pr_err("kfd: ending kernel queue test\n");
+       pr_err("amdkfd: ending kernel queue test\n");
 }
 
 
index 4603897..a39b034 100644 (file)
@@ -164,6 +164,7 @@ void bochs_hw_setmode(struct bochs_device *bochs,
 
        bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
 
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,      0);
        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);
index f38bbcd..acef322 100644 (file)
@@ -11,3 +11,14 @@ config DRM_PTN3460
        select DRM_PANEL
        ---help---
          ptn3460 eDP-LVDS bridge chip driver.
+
+config DRM_PS8622
+       tristate "Parade eDP/LVDS bridge"
+       depends on DRM
+       depends on OF
+       select DRM_PANEL
+       select DRM_KMS_HELPER
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       ---help---
+         parade eDP-LVDS bridge chip driver.
index d8a8cfd..8dfebd9 100644 (file)
@@ -1,4 +1,5 @@
 ccflags-y := -Iinclude/drm
 
+obj-$(CONFIG_DRM_PS8622) += ps8622.o
 obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
 obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
diff --git a/drivers/gpu/drm/bridge/ps8622.c b/drivers/gpu/drm/bridge/ps8622.c
new file mode 100644 (file)
index 0000000..e895aa7
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * Parade PS8622 eDP/LVDS bridge driver
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_panel.h>
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+/* Brightness scale on the Parade chip */
+#define PS8622_MAX_BRIGHTNESS 0xff
+
+/* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */
+#define PS8622_POWER_RISE_T1_MIN_US 10
+#define PS8622_POWER_RISE_T1_MAX_US 10000
+#define PS8622_RST_HIGH_T2_MIN_US 3000
+#define PS8622_RST_HIGH_T2_MAX_US 30000
+#define PS8622_PWMO_END_T12_MS 200
+#define PS8622_POWER_FALL_T16_MAX_US 10000
+#define PS8622_POWER_OFF_T17_MS 500
+
+#if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \
+       (PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US))
+#error "T2.min + T1.max must be less than T2.max + T1.min"
+#endif
+
+struct ps8622_bridge {
+       struct drm_connector connector;
+       struct i2c_client *client;
+       struct drm_bridge bridge;
+       struct drm_panel *panel;
+       struct regulator *v12;
+       struct backlight_device *bl;
+
+       struct gpio_desc *gpio_slp;
+       struct gpio_desc *gpio_rst;
+
+       u32 max_lane_count;
+       u32 lane_count;
+
+       bool enabled;
+};
+
+static inline struct ps8622_bridge *
+               bridge_to_ps8622(struct drm_bridge *bridge)
+{
+       return container_of(bridge, struct ps8622_bridge, bridge);
+}
+
+static inline struct ps8622_bridge *
+               connector_to_ps8622(struct drm_connector *connector)
+{
+       return container_of(connector, struct ps8622_bridge, connector);
+}
+
+static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)
+{
+       int ret;
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msg;
+       u8 data[] = {reg, val};
+
+       msg.addr = client->addr + page;
+       msg.flags = 0;
+       msg.len = sizeof(data);
+       msg.buf = data;
+
+       ret = i2c_transfer(adap, &msg, 1);
+       if (ret != 1)
+               pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n",
+                       client->addr + page, reg, val, ret);
+       return !(ret == 1);
+}
+
+static int ps8622_send_config(struct ps8622_bridge *ps8622)
+{
+       struct i2c_client *cl = ps8622->client;
+       int err = 0;
+
+       /* HPD low */
+       err = ps8622_set(cl, 0x02, 0xa1, 0x01);
+       if (err)
+               goto error;
+
+       /* SW setting: [1:0] SW output 1.2V voltage is lower to 96% */
+       err = ps8622_set(cl, 0x04, 0x14, 0x01);
+       if (err)
+               goto error;
+
+       /* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */
+       err = ps8622_set(cl, 0x04, 0xe3, 0x20);
+       if (err)
+               goto error;
+
+       /* [7] RCO SS enable */
+       err = ps8622_set(cl, 0x04, 0xe2, 0x80);
+       if (err)
+               goto error;
+
+       /* RPHY Setting
+        * [3:2] CDR tune wait cycle before measure for fine tune
+        * b00: 1us b01: 0.5us b10:2us, b11: 4us
+        */
+       err = ps8622_set(cl, 0x04, 0x8a, 0x0c);
+       if (err)
+               goto error;
+
+       /* [3] RFD always on */
+       err = ps8622_set(cl, 0x04, 0x89, 0x08);
+       if (err)
+               goto error;
+
+       /* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times. */
+       err = ps8622_set(cl, 0x04, 0x71, 0x2d);
+       if (err)
+               goto error;
+
+       /* 2.7G CDR settings: NOF=40LSB for HBR CDR  setting */
+       err = ps8622_set(cl, 0x04, 0x7d, 0x07);
+       if (err)
+               goto error;
+
+       /* [1:0] Fmin=+4bands */
+       err = ps8622_set(cl, 0x04, 0x7b, 0x00);
+       if (err)
+               goto error;
+
+       /* [7:5] DCO_FTRNG=+-40% */
+       err = ps8622_set(cl, 0x04, 0x7a, 0xfd);
+       if (err)
+               goto error;
+
+       /* 1.62G CDR settings: [5:2]NOF=64LSB [1:0]DCO scale is 2/5 */
+       err = ps8622_set(cl, 0x04, 0xc0, 0x12);
+       if (err)
+               goto error;
+
+       /* Gitune=-37% */
+       err = ps8622_set(cl, 0x04, 0xc1, 0x92);
+       if (err)
+               goto error;
+
+       /* Fbstep=100% */
+       err = ps8622_set(cl, 0x04, 0xc2, 0x1c);
+       if (err)
+               goto error;
+
+       /* [7] LOS signal disable */
+       err = ps8622_set(cl, 0x04, 0x32, 0x80);
+       if (err)
+               goto error;
+
+       /* RPIO Setting: [7:4] LVDS driver bias current : 75% (250mV swing) */
+       err = ps8622_set(cl, 0x04, 0x00, 0xb0);
+       if (err)
+               goto error;
+
+       /* [7:6] Right-bar GPIO output strength is 8mA */
+       err = ps8622_set(cl, 0x04, 0x15, 0x40);
+       if (err)
+               goto error;
+
+       /* EQ Training State Machine Setting, RCO calibration start */
+       err = ps8622_set(cl, 0x04, 0x54, 0x10);
+       if (err)
+               goto error;
+
+       /* Logic, needs more than 10 I2C command */
+       /* [4:0] MAX_LANE_COUNT set to max supported lanes */
+       err = ps8622_set(cl, 0x01, 0x02, 0x80 | ps8622->max_lane_count);
+       if (err)
+               goto error;
+
+       /* [4:0] LANE_COUNT_SET set to chosen lane count */
+       err = ps8622_set(cl, 0x01, 0x21, 0x80 | ps8622->lane_count);
+       if (err)
+               goto error;
+
+       err = ps8622_set(cl, 0x00, 0x52, 0x20);
+       if (err)
+               goto error;
+
+       /* HPD CP toggle enable */
+       err = ps8622_set(cl, 0x00, 0xf1, 0x03);
+       if (err)
+               goto error;
+
+       err = ps8622_set(cl, 0x00, 0x62, 0x41);
+       if (err)
+               goto error;
+
+       /* Counter number, add 1ms counter delay */
+       err = ps8622_set(cl, 0x00, 0xf6, 0x01);
+       if (err)
+               goto error;
+
+       /* [6]PWM function control by DPCD0040f[7], default is PWM block */
+       err = ps8622_set(cl, 0x00, 0x77, 0x06);
+       if (err)
+               goto error;
+
+       /* 04h Adjust VTotal toleranceto fix the 30Hz no display issue */
+       err = ps8622_set(cl, 0x00, 0x4c, 0x04);
+       if (err)
+               goto error;
+
+       /* DPCD00400='h00, Parade OUI ='h001cf8 */
+       err = ps8622_set(cl, 0x01, 0xc0, 0x00);
+       if (err)
+               goto error;
+
+       /* DPCD00401='h1c */
+       err = ps8622_set(cl, 0x01, 0xc1, 0x1c);
+       if (err)
+               goto error;
+
+       /* DPCD00402='hf8 */
+       err = ps8622_set(cl, 0x01, 0xc2, 0xf8);
+       if (err)
+               goto error;
+
+       /* DPCD403~408 = ASCII code, D2SLV5='h4432534c5635 */
+       err = ps8622_set(cl, 0x01, 0xc3, 0x44);
+       if (err)
+               goto error;
+
+       /* DPCD404 */
+       err = ps8622_set(cl, 0x01, 0xc4, 0x32);
+       if (err)
+               goto error;
+
+       /* DPCD405 */
+       err = ps8622_set(cl, 0x01, 0xc5, 0x53);
+       if (err)
+               goto error;
+
+       /* DPCD406 */
+       err = ps8622_set(cl, 0x01, 0xc6, 0x4c);
+       if (err)
+               goto error;
+
+       /* DPCD407 */
+       err = ps8622_set(cl, 0x01, 0xc7, 0x56);
+       if (err)
+               goto error;
+
+       /* DPCD408 */
+       err = ps8622_set(cl, 0x01, 0xc8, 0x35);
+       if (err)
+               goto error;
+
+       /* DPCD40A, Initial Code major revision '01' */
+       err = ps8622_set(cl, 0x01, 0xca, 0x01);
+       if (err)
+               goto error;
+
+       /* DPCD40B, Initial Code minor revision '05' */
+       err = ps8622_set(cl, 0x01, 0xcb, 0x05);
+       if (err)
+               goto error;
+
+
+       if (ps8622->bl) {
+               /* DPCD720, internal PWM */
+               err = ps8622_set(cl, 0x01, 0xa5, 0xa0);
+               if (err)
+                       goto error;
+
+               /* FFh for 100% brightness, 0h for 0% brightness */
+               err = ps8622_set(cl, 0x01, 0xa7,
+                               ps8622->bl->props.brightness);
+               if (err)
+                       goto error;
+       } else {
+               /* DPCD720, external PWM */
+               err = ps8622_set(cl, 0x01, 0xa5, 0x80);
+               if (err)
+                       goto error;
+       }
+
+       /* Set LVDS output as 6bit-VESA mapping, single LVDS channel */
+       err = ps8622_set(cl, 0x01, 0xcc, 0x13);
+       if (err)
+               goto error;
+
+       /* Enable SSC set by register */
+       err = ps8622_set(cl, 0x02, 0xb1, 0x20);
+       if (err)
+               goto error;
+
+       /* Set SSC enabled and +/-1% central spreading */
+       err = ps8622_set(cl, 0x04, 0x10, 0x16);
+       if (err)
+               goto error;
+
+       /* Logic end */
+       /* MPU Clock source: LC => RCO */
+       err = ps8622_set(cl, 0x04, 0x59, 0x60);
+       if (err)
+               goto error;
+
+       /* LC -> RCO */
+       err = ps8622_set(cl, 0x04, 0x54, 0x14);
+       if (err)
+               goto error;
+
+       /* HPD high */
+       err = ps8622_set(cl, 0x02, 0xa1, 0x91);
+
+error:
+       return err ? -EIO : 0;
+}
+
+static int ps8622_backlight_update(struct backlight_device *bl)
+{
+       struct ps8622_bridge *ps8622 = dev_get_drvdata(&bl->dev);
+       int ret, brightness = bl->props.brightness;
+
+       if (bl->props.power != FB_BLANK_UNBLANK ||
+           bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
+               brightness = 0;
+
+       if (!ps8622->enabled)
+               return -EINVAL;
+
+       ret = ps8622_set(ps8622->client, 0x01, 0xa7, brightness);
+
+       return ret;
+}
+
+static const struct backlight_ops ps8622_backlight_ops = {
+       .update_status  = ps8622_backlight_update,
+};
+
+static void ps8622_pre_enable(struct drm_bridge *bridge)
+{
+       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+       int ret;
+
+       if (ps8622->enabled)
+               return;
+
+       gpiod_set_value(ps8622->gpio_rst, 0);
+
+       if (ps8622->v12) {
+               ret = regulator_enable(ps8622->v12);
+               if (ret)
+                       DRM_ERROR("fails to enable ps8622->v12");
+       }
+
+       if (drm_panel_prepare(ps8622->panel)) {
+               DRM_ERROR("failed to prepare panel\n");
+               return;
+       }
+
+       gpiod_set_value(ps8622->gpio_slp, 1);
+
+       /*
+        * T1 is the range of time that it takes for the power to rise after we
+        * enable the lcd/ps8622 fet. T2 is the range of time in which the
+        * data sheet specifies we should deassert the reset pin.
+        *
+        * If it takes T1.max for the power to rise, we need to wait atleast
+        * T2.min before deasserting the reset pin. If it takes T1.min for the
+        * power to rise, we need to wait at most T2.max before deasserting the
+        * reset pin.
+        */
+       usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US,
+                    PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US);
+
+       gpiod_set_value(ps8622->gpio_rst, 1);
+
+       /* wait 20ms after RST high */
+       usleep_range(20000, 30000);
+
+       ret = ps8622_send_config(ps8622);
+       if (ret) {
+               DRM_ERROR("Failed to send config to bridge (%d)\n", ret);
+               return;
+       }
+
+       ps8622->enabled = true;
+}
+
+static void ps8622_enable(struct drm_bridge *bridge)
+{
+       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+       if (drm_panel_enable(ps8622->panel)) {
+               DRM_ERROR("failed to enable panel\n");
+               return;
+       }
+}
+
+static void ps8622_disable(struct drm_bridge *bridge)
+{
+       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+       if (drm_panel_disable(ps8622->panel)) {
+               DRM_ERROR("failed to disable panel\n");
+               return;
+       }
+       msleep(PS8622_PWMO_END_T12_MS);
+}
+
+static void ps8622_post_disable(struct drm_bridge *bridge)
+{
+       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+       if (!ps8622->enabled)
+               return;
+
+       ps8622->enabled = false;
+
+       /*
+        * This doesn't matter if the regulators are turned off, but something
+        * else might keep them on. In that case, we want to assert the slp gpio
+        * to lower power.
+        */
+       gpiod_set_value(ps8622->gpio_slp, 0);
+
+       if (drm_panel_unprepare(ps8622->panel)) {
+               DRM_ERROR("failed to unprepare panel\n");
+               return;
+       }
+
+       if (ps8622->v12)
+               regulator_disable(ps8622->v12);
+
+       /*
+        * Sleep for at least the amount of time that it takes the power rail to
+        * fall to prevent asserting the rst gpio from doing anything.
+        */
+       usleep_range(PS8622_POWER_FALL_T16_MAX_US,
+                    2 * PS8622_POWER_FALL_T16_MAX_US);
+       gpiod_set_value(ps8622->gpio_rst, 0);
+
+       msleep(PS8622_POWER_OFF_T17_MS);
+}
+
+static int ps8622_get_modes(struct drm_connector *connector)
+{
+       struct ps8622_bridge *ps8622;
+
+       ps8622 = connector_to_ps8622(connector);
+
+       return drm_panel_get_modes(ps8622->panel);
+}
+
+static struct drm_encoder *ps8622_best_encoder(struct drm_connector *connector)
+{
+       struct ps8622_bridge *ps8622;
+
+       ps8622 = connector_to_ps8622(connector);
+
+       return ps8622->bridge.encoder;
+}
+
+static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = {
+       .get_modes = ps8622_get_modes,
+       .best_encoder = ps8622_best_encoder,
+};
+
+static enum drm_connector_status ps8622_detect(struct drm_connector *connector,
+                                                               bool force)
+{
+       return connector_status_connected;
+}
+
+static void ps8622_connector_destroy(struct drm_connector *connector)
+{
+       drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs ps8622_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = ps8622_detect,
+       .destroy = ps8622_connector_destroy,
+};
+
+static int ps8622_attach(struct drm_bridge *bridge)
+{
+       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+       int ret;
+
+       if (!bridge->encoder) {
+               DRM_ERROR("Parent encoder object not found");
+               return -ENODEV;
+       }
+
+       ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD;
+       ret = drm_connector_init(bridge->dev, &ps8622->connector,
+                       &ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+       if (ret) {
+               DRM_ERROR("Failed to initialize connector with drm\n");
+               return ret;
+       }
+       drm_connector_helper_add(&ps8622->connector,
+                                       &ps8622_connector_helper_funcs);
+       drm_connector_register(&ps8622->connector);
+       drm_mode_connector_attach_encoder(&ps8622->connector,
+                                                       bridge->encoder);
+
+       if (ps8622->panel)
+               drm_panel_attach(ps8622->panel, &ps8622->connector);
+
+       drm_helper_hpd_irq_event(ps8622->connector.dev);
+
+       return ret;
+}
+
+static const struct drm_bridge_funcs ps8622_bridge_funcs = {
+       .pre_enable = ps8622_pre_enable,
+       .enable = ps8622_enable,
+       .disable = ps8622_disable,
+       .post_disable = ps8622_post_disable,
+       .attach = ps8622_attach,
+};
+
+static const struct of_device_id ps8622_devices[] = {
+       {.compatible = "parade,ps8622",},
+       {.compatible = "parade,ps8625",},
+       {}
+};
+MODULE_DEVICE_TABLE(of, ps8622_devices);
+
+static int ps8622_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct device_node *endpoint, *panel_node;
+       struct ps8622_bridge *ps8622;
+       int ret;
+
+       ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);
+       if (!ps8622)
+               return -ENOMEM;
+
+       endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+       if (endpoint) {
+               panel_node = of_graph_get_remote_port_parent(endpoint);
+               if (panel_node) {
+                       ps8622->panel = of_drm_find_panel(panel_node);
+                       of_node_put(panel_node);
+                       if (!ps8622->panel)
+                               return -EPROBE_DEFER;
+               }
+       }
+
+       ps8622->client = client;
+
+       ps8622->v12 = devm_regulator_get(dev, "vdd12");
+       if (IS_ERR(ps8622->v12)) {
+               dev_info(dev, "no 1.2v regulator found for PS8622\n");
+               ps8622->v12 = NULL;
+       }
+
+       ps8622->gpio_slp = devm_gpiod_get(dev, "sleep");
+       if (IS_ERR(ps8622->gpio_slp)) {
+               ret = PTR_ERR(ps8622->gpio_slp);
+               dev_err(dev, "cannot get gpio_slp %d\n", ret);
+               return ret;
+       }
+       ret = gpiod_direction_output(ps8622->gpio_slp, 1);
+       if (ret) {
+               dev_err(dev, "cannot configure gpio_slp\n");
+               return ret;
+       }
+
+       ps8622->gpio_rst = devm_gpiod_get(dev, "reset");
+       if (IS_ERR(ps8622->gpio_rst)) {
+               ret = PTR_ERR(ps8622->gpio_rst);
+               dev_err(dev, "cannot get gpio_rst %d\n", ret);
+               return ret;
+       }
+       /*
+        * Assert the reset pin high to avoid the bridge being
+        * initialized prematurely
+        */
+       ret = gpiod_direction_output(ps8622->gpio_rst, 1);
+       if (ret) {
+               dev_err(dev, "cannot configure gpio_rst\n");
+               return ret;
+       }
+
+       ps8622->max_lane_count = id->driver_data;
+
+       if (of_property_read_u32(dev->of_node, "lane-count",
+                                               &ps8622->lane_count)) {
+               ps8622->lane_count = ps8622->max_lane_count;
+       } else if (ps8622->lane_count > ps8622->max_lane_count) {
+               dev_info(dev, "lane-count property is too high,"
+                                               "using max_lane_count\n");
+               ps8622->lane_count = ps8622->max_lane_count;
+       }
+
+       if (!of_find_property(dev->of_node, "use-external-pwm", NULL)) {
+               ps8622->bl = backlight_device_register("ps8622-backlight",
+                               dev, ps8622, &ps8622_backlight_ops,
+                               NULL);
+               if (IS_ERR(ps8622->bl)) {
+                       DRM_ERROR("failed to register backlight\n");
+                       ret = PTR_ERR(ps8622->bl);
+                       ps8622->bl = NULL;
+                       return ret;
+               }
+               ps8622->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS;
+               ps8622->bl->props.brightness = PS8622_MAX_BRIGHTNESS;
+       }
+
+       ps8622->bridge.funcs = &ps8622_bridge_funcs;
+       ps8622->bridge.of_node = dev->of_node;
+       ret = drm_bridge_add(&ps8622->bridge);
+       if (ret) {
+               DRM_ERROR("Failed to add bridge\n");
+               return ret;
+       }
+
+       i2c_set_clientdata(client, ps8622);
+
+       return 0;
+}
+
+static int ps8622_remove(struct i2c_client *client)
+{
+       struct ps8622_bridge *ps8622 = i2c_get_clientdata(client);
+
+       if (ps8622->bl)
+               backlight_device_unregister(ps8622->bl);
+
+       drm_bridge_remove(&ps8622->bridge);
+
+       return 0;
+}
+
+static const struct i2c_device_id ps8622_i2c_table[] = {
+       /* Device type, max_lane_count */
+       {"ps8622", 1},
+       {"ps8625", 2},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
+
+static struct i2c_driver ps8622_driver = {
+       .id_table       = ps8622_i2c_table,
+       .probe          = ps8622_probe,
+       .remove         = ps8622_remove,
+       .driver         = {
+               .name   = "ps8622",
+               .owner  = THIS_MODULE,
+               .of_match_table = ps8622_devices,
+       },
+};
+module_i2c_driver(ps8622_driver);
+
+MODULE_AUTHOR("Vincent Palatin <vpalatin@chromium.org>");
+MODULE_DESCRIPTION("Parade ps8622/ps8625 eDP-LVDS converter driver");
+MODULE_LICENSE("GPL v2");
index 826833e..9d2f053 100644 (file)
@@ -265,7 +265,7 @@ static struct drm_connector_funcs ptn3460_connector_funcs = {
        .destroy = ptn3460_connector_destroy,
 };
 
-int ptn3460_bridge_attach(struct drm_bridge *bridge)
+static int ptn3460_bridge_attach(struct drm_bridge *bridge)
 {
        struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
        int ret;
index a6caaae..57efdbe 100644 (file)
@@ -134,6 +134,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                connector->funcs->atomic_destroy_state(connector,
                                                       state->connector_states[i]);
+               state->connectors[i] = NULL;
                state->connector_states[i] = NULL;
        }
 
@@ -145,6 +146,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                crtc->funcs->atomic_destroy_state(crtc,
                                                  state->crtc_states[i]);
+               state->crtcs[i] = NULL;
                state->crtc_states[i] = NULL;
        }
 
@@ -156,6 +158,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                plane->funcs->atomic_destroy_state(plane,
                                                   state->plane_states[i]);
+               state->planes[i] = NULL;
                state->plane_states[i] = NULL;
        }
 }
@@ -170,6 +173,9 @@ EXPORT_SYMBOL(drm_atomic_state_clear);
  */
 void drm_atomic_state_free(struct drm_atomic_state *state)
 {
+       if (!state)
+               return;
+
        drm_atomic_state_clear(state);
 
        DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state);
@@ -248,11 +254,14 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
        struct drm_mode_config *config = &dev->mode_config;
 
        /* FIXME: Mode prop is missing, which also controls ->enable. */
-       if (property == config->prop_active) {
+       if (property == config->prop_active)
                state->active = val;
-       else if (crtc->funcs->atomic_set_property)
+       else if (crtc->funcs->atomic_set_property)
                return crtc->funcs->atomic_set_property(crtc, state, property, val);
-       return -EINVAL;
+       else
+               return -EINVAL;
+
+       return 0;
 }
 EXPORT_SYMBOL(drm_atomic_crtc_set_property);
 
@@ -266,9 +275,17 @@ int drm_atomic_crtc_get_property(struct drm_crtc *crtc,
                const struct drm_crtc_state *state,
                struct drm_property *property, uint64_t *val)
 {
-       if (crtc->funcs->atomic_get_property)
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *config = &dev->mode_config;
+
+       if (property == config->prop_active)
+               *val = state->active;
+       else if (crtc->funcs->atomic_get_property)
                return crtc->funcs->atomic_get_property(crtc, state, property, val);
-       return -EINVAL;
+       else
+               return -EINVAL;
+
+       return 0;
 }
 
 /**
index d9ed9a5..41c38ed 100644 (file)
@@ -587,7 +587,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)];
 
-               if (!old_crtc_state->active)
+               if (!old_crtc_state->active ||
+                   !needs_modeset(old_conn_state->crtc->state))
                        continue;
 
                encoder = old_conn_state->best_encoder;
@@ -847,7 +848,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
                if (!connector || !connector->state->best_encoder)
                        continue;
 
-               if (!connector->state->crtc->state->active)
+               if (!connector->state->crtc->state->active ||
+                   !needs_modeset(connector->state->crtc->state))
                        continue;
 
                encoder = connector->state->best_encoder;
@@ -2067,6 +2069,26 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
 EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
 
 /**
+ * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
+ * @crtc: CRTC object
+ * @state: atomic CRTC state
+ *
+ * Copies atomic state from a CRTC's current state and resets inferred values.
+ * This is useful for drivers that subclass the CRTC state.
+ */
+void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
+                                             struct drm_crtc_state *state)
+{
+       memcpy(state, crtc->state, sizeof(*state));
+
+       state->mode_changed = false;
+       state->active_changed = false;
+       state->planes_changed = false;
+       state->event = NULL;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
+
+/**
  * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
  * @crtc: drm CRTC
  *
@@ -2081,20 +2103,35 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
        if (WARN_ON(!crtc->state))
                return NULL;
 
-       state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL);
-
-       if (state) {
-               state->mode_changed = false;
-               state->active_changed = false;
-               state->planes_changed = false;
-               state->event = NULL;
-       }
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               __drm_atomic_helper_crtc_duplicate_state(crtc, state);
 
        return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
 
 /**
+ * __drm_atomic_helper_crtc_destroy_state - release CRTC state
+ * @crtc: CRTC object
+ * @state: CRTC state object to release
+ *
+ * Releases all resources stored in the CRTC state without actually freeing
+ * the memory of the CRTC state. This is useful for drivers that subclass the
+ * CRTC state.
+ */
+void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+                                           struct drm_crtc_state *state)
+{
+       /*
+        * This is currently a placeholder so that drivers that subclass the
+        * state will automatically do the right thing if code is ever added
+        * to this function.
+        */
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
+
+/**
  * drm_atomic_helper_crtc_destroy_state - default state destroy hook
  * @crtc: drm CRTC
  * @state: CRTC state object to release
@@ -2105,6 +2142,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
 void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
                                          struct drm_crtc_state *state)
 {
+       __drm_atomic_helper_crtc_destroy_state(crtc, state);
        kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
@@ -2130,6 +2168,24 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
 EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
 
 /**
+ * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
+ * @plane: plane object
+ * @state: atomic plane state
+ *
+ * Copies atomic state from a plane's current state. This is useful for
+ * drivers that subclass the plane state.
+ */
+void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
+                                              struct drm_plane_state *state)
+{
+       memcpy(state, plane->state, sizeof(*state));
+
+       if (state->fb)
+               drm_framebuffer_reference(state->fb);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
+
+/**
  * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
  * @plane: drm plane
  *
@@ -2144,16 +2200,32 @@ drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
        if (WARN_ON(!plane->state))
                return NULL;
 
-       state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
-
-       if (state && state->fb)
-               drm_framebuffer_reference(state->fb);
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               __drm_atomic_helper_plane_duplicate_state(plane, state);
 
        return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
 
 /**
+ * __drm_atomic_helper_plane_destroy_state - release plane state
+ * @plane: plane object
+ * @state: plane state object to release
+ *
+ * Releases all resources stored in the plane state without actually freeing
+ * the memory of the plane state. This is useful for drivers that subclass the
+ * plane state.
+ */
+void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+                                            struct drm_plane_state *state)
+{
+       if (state->fb)
+               drm_framebuffer_unreference(state->fb);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
+
+/**
  * drm_atomic_helper_plane_destroy_state - default state destroy hook
  * @plane: drm plane
  * @state: plane state object to release
@@ -2164,9 +2236,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
                                           struct drm_plane_state *state)
 {
-       if (state->fb)
-               drm_framebuffer_unreference(state->fb);
-
+       __drm_atomic_helper_plane_destroy_state(plane, state);
        kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
@@ -2190,6 +2260,22 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector)
 EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 
 /**
+ * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
+ * @connector: connector object
+ * @state: atomic connector state
+ *
+ * Copies atomic state from a connector's current state. This is useful for
+ * drivers that subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
+                                           struct drm_connector_state *state)
+{
+       memcpy(state, connector->state, sizeof(*state));
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
+
+/**
  * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
  * @connector: drm connector
  *
@@ -2199,14 +2285,41 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 struct drm_connector_state *
 drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
 {
+       struct drm_connector_state *state;
+
        if (WARN_ON(!connector->state))
                return NULL;
 
-       return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL);
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               __drm_atomic_helper_connector_duplicate_state(connector, state);
+
+       return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
 
 /**
+ * __drm_atomic_helper_connector_destroy_state - release connector state
+ * @connector: connector object
+ * @state: connector state object to release
+ *
+ * Releases all resources stored in the connector state without actually
+ * freeing the memory of the connector state. This is useful for drivers that
+ * subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+                                           struct drm_connector_state *state)
+{
+       /*
+        * This is currently a placeholder so that drivers that subclass the
+        * state will automatically do the right thing if code is ever added
+        * to this function.
+        */
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
+
+/**
  * drm_atomic_helper_connector_destroy_state - default state destroy hook
  * @connector: drm connector
  * @state: connector state object to release
@@ -2217,6 +2330,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
 void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
                                          struct drm_connector_state *state)
 {
+       __drm_atomic_helper_connector_destroy_state(connector, state);
        kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
index d576a4d..b3989e2 100644 (file)
@@ -5599,6 +5599,7 @@ struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
        mutex_unlock(&dev->mode_config.idr_mutex);
        return NULL;
 }
+EXPORT_SYMBOL(drm_mode_get_tile_group);
 
 /**
  * drm_mode_create_tile_group - create a tile group from a displayid description
@@ -5637,3 +5638,4 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
        mutex_unlock(&dev->mode_config.idr_mutex);
        return tg;
 }
+EXPORT_SYMBOL(drm_mode_create_tile_group);
index 3053aab..dd895c4 100644 (file)
@@ -270,7 +270,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                              struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_display_mode *adjusted_mode, saved_mode;
+       struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
        struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        struct drm_encoder_helper_funcs *encoder_funcs;
        int saved_x, saved_y;
@@ -292,6 +292,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        }
 
        saved_mode = crtc->mode;
+       saved_hwmode = crtc->hwmode;
        saved_x = crtc->x;
        saved_y = crtc->y;
 
@@ -334,6 +335,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        }
        DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
+       crtc->hwmode = *adjusted_mode;
+
        /* Prepare the encoders and CRTCs before setting the mode. */
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 
@@ -396,9 +399,6 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                        encoder->bridge->funcs->enable(encoder->bridge);
        }
 
-       /* Store real post-adjustment hardware mode. */
-       crtc->hwmode = *adjusted_mode;
-
        /* Calculate and store various constants which
         * are later needed by vblank and swap-completion
         * timestamping. They are derived from true hwmode.
@@ -411,6 +411,7 @@ done:
        if (!ret) {
                crtc->enabled = saved_enabled;
                crtc->mode = saved_mode;
+               crtc->hwmode = saved_hwmode;
                crtc->x = saved_x;
                crtc->y = saved_y;
        }
index d5368ea..71dcbc6 100644 (file)
@@ -462,7 +462,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                        break;
 
                case DP_AUX_NATIVE_REPLY_NACK:
-                       DRM_DEBUG_KMS("native nack\n");
+                       DRM_DEBUG_KMS("native nack (result=%d, size=%zu)\n", ret, msg->size);
                        return -EREMOTEIO;
 
                case DP_AUX_NATIVE_REPLY_DEFER:
@@ -493,7 +493,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                        return ret;
 
                case DP_AUX_I2C_REPLY_NACK:
-                       DRM_DEBUG_KMS("I2C nack\n");
+                       DRM_DEBUG_KMS("I2C nack (result=%d, size=%zu\n", ret, msg->size);
                        aux->i2c_nack_count++;
                        return -EREMOTEIO;
 
index 732cb6f..4c0aa97 100644 (file)
@@ -287,6 +287,7 @@ int drm_load_edid_firmware(struct drm_connector *connector)
 
        drm_mode_connector_update_edid_property(connector, edid);
        ret = drm_add_edid_modes(connector, edid);
+       drm_edid_to_eld(connector, edid);
        kfree(edid);
 
        return ret;
index 1a20db7..309b947 100644 (file)
@@ -1283,12 +1283,12 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
                                                      int width, int height)
 {
        struct drm_cmdline_mode *cmdline_mode;
-       struct drm_display_mode *mode = NULL;
+       struct drm_display_mode *mode;
        bool prefer_non_interlace;
 
        cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
        if (cmdline_mode->specified == false)
-               return mode;
+               return NULL;
 
        /* attempt to find a matching mode in the list of modes
         *  we have gotten so far, if not add a CVT mode that conforms
@@ -1297,7 +1297,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
                goto create_mode;
 
        prefer_non_interlace = !cmdline_mode->interlace;
- again:
+again:
        list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
                /* check width/height */
                if (mode->hdisplay != cmdline_mode->xres ||
index a6d773a..266dcd6 100644 (file)
@@ -524,8 +524,13 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
        return 0;
 }
 
-#define DRM_IOCTL_DEF(ioctl, _func, _flags) \
-       [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl}
+#define DRM_IOCTL_DEF(ioctl, _func, _flags)    \
+       [DRM_IOCTL_NR(ioctl)] = {               \
+               .cmd = ioctl,                   \
+               .func = _func,                  \
+               .flags = _flags,                \
+               .name = #ioctl                  \
+       }
 
 /** Ioctl table */
 static const struct drm_ioctl_desc drm_ioctls[] = {
@@ -663,39 +668,29 @@ long drm_ioctl(struct file *filp,
        int retcode = -EINVAL;
        char stack_kdata[128];
        char *kdata = NULL;
-       unsigned int usize, asize;
+       unsigned int usize, asize, drv_size;
 
        dev = file_priv->minor->dev;
 
        if (drm_device_is_unplugged(dev))
                return -ENODEV;
 
-       if ((nr >= DRM_CORE_IOCTL_COUNT) &&
-           ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
-               goto err_i1;
-       if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) &&
-           (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) {
-               u32 drv_size;
+       if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END) {
+               /* driver ioctl */
+               if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
+                       goto err_i1;
                ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
-               drv_size = _IOC_SIZE(ioctl->cmd_drv);
-               usize = asize = _IOC_SIZE(cmd);
-               if (drv_size > asize)
-                       asize = drv_size;
-               cmd = ioctl->cmd_drv;
-       }
-       else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
-               u32 drv_size;
-
+       } else {
+               /* core ioctl */
+               if (nr >= DRM_CORE_IOCTL_COUNT)
+                       goto err_i1;
                ioctl = &drm_ioctls[nr];
+       }
 
-               drv_size = _IOC_SIZE(ioctl->cmd);
-               usize = asize = _IOC_SIZE(cmd);
-               if (drv_size > asize)
-                       asize = drv_size;
-
-               cmd = ioctl->cmd;
-       } else
-               goto err_i1;
+       drv_size = _IOC_SIZE(ioctl->cmd);
+       usize = _IOC_SIZE(cmd);
+       asize = max(usize, drv_size);
+       cmd = ioctl->cmd;
 
        DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
                  task_pid_nr(current),
@@ -776,12 +771,13 @@ EXPORT_SYMBOL(drm_ioctl);
  */
 bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
 {
-       if ((nr >= DRM_COMMAND_END && nr < DRM_CORE_IOCTL_COUNT) ||
-           (nr < DRM_COMMAND_BASE)) {
-               *flags = drm_ioctls[nr].flags;
-               return true;
-       }
+       if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END)
+               return false;
+
+       if (nr >= DRM_CORE_IOCTL_COUNT)
+               return false;
 
-       return false;
+       *flags = drm_ioctls[nr].flags;
+       return true;
 }
 EXPORT_SYMBOL(drm_ioctl_flags);
index 2cca85f..213b11e 100644 (file)
@@ -903,6 +903,12 @@ EXPORT_SYMBOL(drm_mode_duplicate);
  */
 bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
 {
+       if (!mode1 && !mode2)
+               return true;
+
+       if (!mode1 || !mode2)
+               return false;
+
        /* do clock check convert to PICOS so fb modes get matched
         * the same */
        if (mode1->clock && mode2->clock) {
@@ -1148,7 +1154,7 @@ EXPORT_SYMBOL(drm_mode_sort);
 /**
  * drm_mode_connector_list_update - update the mode list for the connector
  * @connector: the connector to update
- * @merge_type_bits: whether to merge or overright type bits.
+ * @merge_type_bits: whether to merge or overwrite type bits
  *
  * This moves the modes from the @connector probed_modes list
  * to the actual mode list. It compares the probed mode against the current
index 16150a0..aaa1307 100644 (file)
@@ -43,14 +43,10 @@ static uint32_t drm_crtc_port_mask(struct drm_device *dev,
 uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
                                    struct device_node *port)
 {
-       struct device_node *remote_port, *ep = NULL;
+       struct device_node *remote_port, *ep;
        uint32_t possible_crtcs = 0;
 
-       do {
-               ep = of_graph_get_next_endpoint(port, ep);
-               if (!ep)
-                       break;
-
+       for_each_endpoint_of_node(port, ep) {
                remote_port = of_graph_get_remote_port(ep);
                if (!remote_port) {
                        of_node_put(ep);
@@ -60,7 +56,7 @@ uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
                possible_crtcs |= drm_crtc_port_mask(dev, remote_port);
 
                of_node_put(remote_port);
-       } while (1);
+       }
 
        return possible_crtcs;
 }
index 6591d48..3fee587 100644 (file)
@@ -174,6 +174,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
                        struct edid *edid = (struct edid *) connector->edid_blob_ptr->data;
 
                        count = drm_add_edid_modes(connector, edid);
+                       drm_edid_to_eld(connector, edid);
                } else
                        count = (*connector_funcs->get_modes)(connector);
        }
index a5e7461..0a67803 100644 (file)
@@ -50,7 +50,7 @@ config DRM_EXYNOS_DSI
 
 config DRM_EXYNOS_DP
        bool "EXYNOS DRM DP driver support"
-       depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
+       depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
        default DRM_EXYNOS
        select DRM_PANEL
        help
index 63f02e2..1f7e33f 100644 (file)
@@ -28,6 +28,7 @@
 #include <video/exynos7_decon.h>
 
 #include "exynos_drm_crtc.h"
+#include "exynos_drm_plane.h"
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fbdev.h"
 #include "exynos_drm_iommu.h"
 
 #define WINDOWS_NR     2
 
-struct decon_win_data {
-       unsigned int            ovl_x;
-       unsigned int            ovl_y;
-       unsigned int            offset_x;
-       unsigned int            offset_y;
-       unsigned int            ovl_width;
-       unsigned int            ovl_height;
-       unsigned int            fb_width;
-       unsigned int            fb_height;
-       unsigned int            bpp;
-       unsigned int            pixel_format;
-       dma_addr_t              dma_addr;
-       bool                    enabled;
-       bool                    resume;
-};
-
 struct decon_context {
        struct device                   *dev;
        struct drm_device               *drm_dev;
        struct exynos_drm_crtc          *crtc;
+       struct exynos_drm_plane         planes[WINDOWS_NR];
        struct clk                      *pclk;
        struct clk                      *aclk;
        struct clk                      *eclk;
        struct clk                      *vclk;
        void __iomem                    *regs;
-       struct decon_win_data           win_data[WINDOWS_NR];
        unsigned int                    default_win;
        unsigned long                   irq_flags;
        bool                            i80_if;
@@ -296,59 +281,16 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
        }
 }
 
-static void decon_win_mode_set(struct exynos_drm_crtc *crtc,
-                       struct exynos_drm_plane *plane)
-{
-       struct decon_context *ctx = crtc->ctx;
-       struct decon_win_data *win_data;
-       int win, padding;
-
-       if (!plane) {
-               DRM_ERROR("plane is NULL\n");
-               return;
-       }
-
-       win = plane->zpos;
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-
-       win_data = &ctx->win_data[win];
-
-       padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
-       win_data->offset_x = plane->fb_x;
-       win_data->offset_y = plane->fb_y;
-       win_data->fb_width = plane->fb_width + padding;
-       win_data->fb_height = plane->fb_height;
-       win_data->ovl_x = plane->crtc_x;
-       win_data->ovl_y = plane->crtc_y;
-       win_data->ovl_width = plane->crtc_width;
-       win_data->ovl_height = plane->crtc_height;
-       win_data->dma_addr = plane->dma_addr[0];
-       win_data->bpp = plane->bpp;
-       win_data->pixel_format = plane->pixel_format;
-
-       DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
-                       win_data->offset_x, win_data->offset_y);
-       DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       win_data->ovl_width, win_data->ovl_height);
-       DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
-       DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
-                       plane->fb_width, plane->crtc_width);
-}
-
 static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
 {
-       struct decon_win_data *win_data = &ctx->win_data[win];
+       struct exynos_drm_plane *plane = &ctx->planes[win];
        unsigned long val;
+       int padding;
 
        val = readl(ctx->regs + WINCON(win));
        val &= ~WINCONx_BPPMODE_MASK;
 
-       switch (win_data->pixel_format) {
+       switch (plane->pixel_format) {
        case DRM_FORMAT_RGB565:
                val |= WINCONx_BPPMODE_16BPP_565;
                val |= WINCONx_BURSTLEN_16WORD;
@@ -397,7 +339,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
                break;
        }
 
-       DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
+       DRM_DEBUG_KMS("bpp = %d\n", plane->bpp);
 
        /*
         * In case of exynos, setting dma-burst to 16Word causes permanent
@@ -407,7 +349,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
         * movement causes unstable DMA which results into iommu crash/tear.
         */
 
-       if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+       padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
+       if (plane->fb_width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) {
                val &= ~WINCONx_BURSTLEN_MASK;
                val |= WINCONx_BURSTLEN_8WORD;
        }
@@ -435,7 +378,7 @@ static void decon_win_set_colkey(struct decon_context *ctx, unsigned int win)
  * @protect: 1 to protect (disable updates)
  */
 static void decon_shadow_protect_win(struct decon_context *ctx,
-                                                       int win, bool protect)
+                                    unsigned int win, bool protect)
 {
        u32 bits, val;
 
@@ -449,12 +392,12 @@ static void decon_shadow_protect_win(struct decon_context *ctx,
        writel(val, ctx->regs + SHADOWCON);
 }
 
-static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
+static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct decon_context *ctx = crtc->ctx;
        struct drm_display_mode *mode = &crtc->base.mode;
-       struct decon_win_data *win_data;
-       int win = zpos;
+       struct exynos_drm_plane *plane;
+       int padding;
        unsigned long val, alpha;
        unsigned int last_x;
        unsigned int last_y;
@@ -462,17 +405,14 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        if (ctx->suspended)
                return;
 
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
        /* If suspended, enable this on resume */
        if (ctx->suspended) {
-               win_data->resume = true;
+               plane->resume = true;
                return;
        }
 
@@ -490,39 +430,41 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        decon_shadow_protect_win(ctx, win, true);
 
        /* buffer start address */
-       val = (unsigned long)win_data->dma_addr;
+       val = (unsigned long)plane->dma_addr[0];
        writel(val, ctx->regs + VIDW_BUF_START(win));
 
+       padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
+
        /* buffer size */
-       writel(win_data->fb_width, ctx->regs + VIDW_WHOLE_X(win));
-       writel(win_data->fb_height, ctx->regs + VIDW_WHOLE_Y(win));
+       writel(plane->fb_width + padding, ctx->regs + VIDW_WHOLE_X(win));
+       writel(plane->fb_height, ctx->regs + VIDW_WHOLE_Y(win));
 
        /* offset from the start of the buffer to read */
-       writel(win_data->offset_x, ctx->regs + VIDW_OFFSET_X(win));
-       writel(win_data->offset_y, ctx->regs + VIDW_OFFSET_Y(win));
+       writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win));
+       writel(plane->src_y, ctx->regs + VIDW_OFFSET_Y(win));
 
        DRM_DEBUG_KMS("start addr = 0x%lx\n",
-                       (unsigned long)win_data->dma_addr);
+                       (unsigned long)val);
        DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       win_data->ovl_width, win_data->ovl_height);
+                       plane->crtc_width, plane->crtc_height);
 
        /*
         * OSD position.
         * In case the window layout goes of LCD layout, DECON fails.
         */
-       if ((win_data->ovl_x + win_data->ovl_width) > mode->hdisplay)
-               win_data->ovl_x = mode->hdisplay - win_data->ovl_width;
-       if ((win_data->ovl_y + win_data->ovl_height) > mode->vdisplay)
-               win_data->ovl_y = mode->vdisplay - win_data->ovl_height;
+       if ((plane->crtc_x + plane->crtc_width) > mode->hdisplay)
+               plane->crtc_x = mode->hdisplay - plane->crtc_width;
+       if ((plane->crtc_y + plane->crtc_height) > mode->vdisplay)
+               plane->crtc_y = mode->vdisplay - plane->crtc_height;
 
-       val = VIDOSDxA_TOPLEFT_X(win_data->ovl_x) |
-               VIDOSDxA_TOPLEFT_Y(win_data->ovl_y);
+       val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) |
+               VIDOSDxA_TOPLEFT_Y(plane->crtc_y);
        writel(val, ctx->regs + VIDOSD_A(win));
 
-       last_x = win_data->ovl_x + win_data->ovl_width;
+       last_x = plane->crtc_x + plane->crtc_width;
        if (last_x)
                last_x--;
-       last_y = win_data->ovl_y + win_data->ovl_height;
+       last_y = plane->crtc_y + plane->crtc_height;
        if (last_y)
                last_y--;
 
@@ -531,7 +473,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        writel(val, ctx->regs + VIDOSD_B(win));
 
        DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
-                       win_data->ovl_x, win_data->ovl_y, last_x, last_y);
+                       plane->crtc_x, plane->crtc_y, last_x, last_y);
 
        /* OSD alpha */
        alpha = VIDOSDxC_ALPHA0_R_F(0x0) |
@@ -565,27 +507,23 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        val |= DECON_UPDATE_STANDALONE_F;
        writel(val, ctx->regs + DECON_UPDATE);
 
-       win_data->enabled = true;
+       plane->enabled = true;
 }
 
-static void decon_win_disable(struct exynos_drm_crtc *crtc, int zpos)
+static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct decon_context *ctx = crtc->ctx;
-       struct decon_win_data *win_data;
-       int win = zpos;
+       struct exynos_drm_plane *plane;
        u32 val;
 
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
        if (ctx->suspended) {
                /* do not resume this window*/
-               win_data->resume = false;
+               plane->resume = false;
                return;
        }
 
@@ -604,42 +542,42 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, int zpos)
        val |= DECON_UPDATE_STANDALONE_F;
        writel(val, ctx->regs + DECON_UPDATE);
 
-       win_data->enabled = false;
+       plane->enabled = false;
 }
 
 static void decon_window_suspend(struct decon_context *ctx)
 {
-       struct decon_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->resume = win_data->enabled;
-               if (win_data->enabled)
+               plane = &ctx->planes[i];
+               plane->resume = plane->enabled;
+               if (plane->enabled)
                        decon_win_disable(ctx->crtc, i);
        }
 }
 
 static void decon_window_resume(struct decon_context *ctx)
 {
-       struct decon_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->enabled = win_data->resume;
-               win_data->resume = false;
+               plane = &ctx->planes[i];
+               plane->enabled = plane->resume;
+               plane->resume = false;
        }
 }
 
 static void decon_apply(struct decon_context *ctx)
 {
-       struct decon_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               if (win_data->enabled)
+               plane = &ctx->planes[i];
+               if (plane->enabled)
                        decon_win_commit(ctx->crtc, i);
                else
                        decon_win_disable(ctx->crtc, i);
@@ -779,7 +717,6 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = {
        .enable_vblank = decon_enable_vblank,
        .disable_vblank = decon_disable_vblank,
        .wait_for_vblank = decon_wait_for_vblank,
-       .win_mode_set = decon_win_mode_set,
        .win_commit = decon_win_commit,
        .win_disable = decon_win_disable,
 };
@@ -818,6 +755,9 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
 {
        struct decon_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
+       struct exynos_drm_plane *exynos_plane;
+       enum drm_plane_type type;
+       unsigned int zpos;
        int ret;
 
        ret = decon_ctx_initialize(ctx, drm_dev);
@@ -826,8 +766,18 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
                return ret;
        }
 
-       ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
-                                          EXYNOS_DISPLAY_TYPE_LCD,
+       for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
+               type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
+                                               DRM_PLANE_TYPE_OVERLAY;
+               ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
+                                       1 << ctx->pipe, type, zpos);
+               if (ret)
+                       return ret;
+       }
+
+       exynos_plane = &ctx->planes[ctx->default_win];
+       ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
+                                          ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
                                           &decon_crtc_ops, ctx);
        if (IS_ERR(ctx->crtc)) {
                decon_ctx_remove(ctx);
@@ -888,8 +838,8 @@ static int decon_probe(struct platform_device *pdev)
        of_node_put(i80_if_timings);
 
        ctx->regs = of_iomap(dev->of_node, 0);
-       if (IS_ERR(ctx->regs)) {
-               ret = PTR_ERR(ctx->regs);
+       if (!ctx->regs) {
+               ret = -ENOMEM;
                goto err_del_component;
        }
 
index bf17a60..1dbfba5 100644 (file)
 #include <drm/bridge/ptn3460.h>
 
 #include "exynos_dp_core.h"
+#include "exynos_drm_fimd.h"
 
 #define ctx_from_connector(c)  container_of(c, struct exynos_dp_device, \
                                        connector)
 
+static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp)
+{
+       return to_exynos_crtc(dp->encoder->crtc);
+}
+
 static inline struct exynos_dp_device *
 display_to_dp(struct exynos_drm_display *d)
 {
@@ -1070,6 +1076,8 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp)
                }
        }
 
+       fimd_dp_clock_enable(dp_to_crtc(dp), true);
+
        clk_prepare_enable(dp->clock);
        exynos_dp_phy_init(dp);
        exynos_dp_init_dp(dp);
@@ -1094,6 +1102,8 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp)
        exynos_dp_phy_exit(dp);
        clk_disable_unprepare(dp->clock);
 
+       fimd_dp_clock_enable(dp_to_crtc(dp), false);
+
        if (dp->panel) {
                if (drm_panel_unprepare(dp->panel))
                        DRM_ERROR("failed to turnoff the panel\n");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
deleted file mode 100644 (file)
index ba9b3d5..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *     Inki Dae <inki.dae@samsung.com>
- *     Joonyoung Shim <jy0922.shim@samsung.com>
- *     Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-
-#include <drm/exynos_drm.h>
-#include "exynos_drm_drv.h"
-#include "exynos_drm_encoder.h"
-#include "exynos_drm_connector.h"
-
-#define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
-                               drm_connector)
-
-struct exynos_drm_connector {
-       struct drm_connector            drm_connector;
-       uint32_t                        encoder_id;
-       struct exynos_drm_display       *display;
-};
-
-static int exynos_drm_connector_get_modes(struct drm_connector *connector)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       struct edid *edid = NULL;
-       unsigned int count = 0;
-       int ret;
-
-       /*
-        * if get_edid() exists then get_edid() callback of hdmi side
-        * is called to get edid data through i2c interface else
-        * get timing from the FIMD driver(display controller).
-        *
-        * P.S. in case of lcd panel, count is always 1 if success
-        * because lcd panel has only one mode.
-        */
-       if (display->ops->get_edid) {
-               edid = display->ops->get_edid(display, connector);
-               if (IS_ERR_OR_NULL(edid)) {
-                       ret = PTR_ERR(edid);
-                       edid = NULL;
-                       DRM_ERROR("Panel operation get_edid failed %d\n", ret);
-                       goto out;
-               }
-
-               count = drm_add_edid_modes(connector, edid);
-               if (!count) {
-                       DRM_ERROR("Add edid modes failed %d\n", count);
-                       goto out;
-               }
-
-               drm_mode_connector_update_edid_property(connector, edid);
-       } else {
-               struct exynos_drm_panel_info *panel;
-               struct drm_display_mode *mode = drm_mode_create(connector->dev);
-               if (!mode) {
-                       DRM_ERROR("failed to create a new display mode.\n");
-                       return 0;
-               }
-
-               if (display->ops->get_panel)
-                       panel = display->ops->get_panel(display);
-               else {
-                       drm_mode_destroy(connector->dev, mode);
-                       return 0;
-               }
-
-               drm_display_mode_from_videomode(&panel->vm, mode);
-               mode->width_mm = panel->width_mm;
-               mode->height_mm = panel->height_mm;
-               connector->display_info.width_mm = mode->width_mm;
-               connector->display_info.height_mm = mode->height_mm;
-
-               mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-               drm_mode_set_name(mode);
-               drm_mode_probed_add(connector, mode);
-
-               count = 1;
-       }
-
-out:
-       kfree(edid);
-       return count;
-}
-
-static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
-                                           struct drm_display_mode *mode)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       int ret = MODE_BAD;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (display->ops->check_mode)
-               if (!display->ops->check_mode(display, mode))
-                       ret = MODE_OK;
-
-       return ret;
-}
-
-static struct drm_encoder *exynos_drm_best_encoder(
-               struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       return drm_encoder_find(dev, exynos_connector->encoder_id);
-}
-
-static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
-       .get_modes      = exynos_drm_connector_get_modes,
-       .mode_valid     = exynos_drm_connector_mode_valid,
-       .best_encoder   = exynos_drm_best_encoder,
-};
-
-static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
-                               unsigned int max_width, unsigned int max_height)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       unsigned int width, height;
-
-       width = max_width;
-       height = max_height;
-
-       /*
-        * if specific driver want to find desired_mode using maxmum
-        * resolution then get max width and height from that driver.
-        */
-       if (display->ops->get_max_resol)
-               display->ops->get_max_resol(display, &width, &height);
-
-       return drm_helper_probe_single_connector_modes(connector, width,
-                                                       height);
-}
-
-/* get detection status of display device. */
-static enum drm_connector_status
-exynos_drm_connector_detect(struct drm_connector *connector, bool force)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       enum drm_connector_status status = connector_status_disconnected;
-
-       if (display->ops->is_connected) {
-               if (display->ops->is_connected(display))
-                       status = connector_status_connected;
-               else
-                       status = connector_status_disconnected;
-       }
-
-       return status;
-}
-
-static void exynos_drm_connector_destroy(struct drm_connector *connector)
-{
-       struct exynos_drm_connector *exynos_connector =
-               to_exynos_connector(connector);
-
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
-       kfree(exynos_connector);
-}
-
-static struct drm_connector_funcs exynos_connector_funcs = {
-       .dpms           = drm_helper_connector_dpms,
-       .fill_modes     = exynos_drm_connector_fill_modes,
-       .detect         = exynos_drm_connector_detect,
-       .destroy        = exynos_drm_connector_destroy,
-};
-
-struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
-                                                  struct drm_encoder *encoder)
-{
-       struct exynos_drm_connector *exynos_connector;
-       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
-       struct drm_connector *connector;
-       int type;
-       int err;
-
-       exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
-       if (!exynos_connector)
-               return NULL;
-
-       connector = &exynos_connector->drm_connector;
-
-       switch (display->type) {
-       case EXYNOS_DISPLAY_TYPE_HDMI:
-               type = DRM_MODE_CONNECTOR_HDMIA;
-               connector->interlace_allowed = true;
-               connector->polled = DRM_CONNECTOR_POLL_HPD;
-               break;
-       case EXYNOS_DISPLAY_TYPE_VIDI:
-               type = DRM_MODE_CONNECTOR_VIRTUAL;
-               connector->polled = DRM_CONNECTOR_POLL_HPD;
-               break;
-       default:
-               type = DRM_MODE_CONNECTOR_Unknown;
-               break;
-       }
-
-       drm_connector_init(dev, connector, &exynos_connector_funcs, type);
-       drm_connector_helper_add(connector, &exynos_connector_helper_funcs);
-
-       err = drm_connector_register(connector);
-       if (err)
-               goto err_connector;
-
-       exynos_connector->encoder_id = encoder->base.id;
-       exynos_connector->display = display;
-       connector->dpms = DRM_MODE_DPMS_OFF;
-       connector->encoder = encoder;
-
-       err = drm_mode_connector_attach_encoder(connector, encoder);
-       if (err) {
-               DRM_ERROR("failed to attach a connector to a encoder\n");
-               goto err_sysfs;
-       }
-
-       DRM_DEBUG_KMS("connector has been created\n");
-
-       return connector;
-
-err_sysfs:
-       drm_connector_unregister(connector);
-err_connector:
-       drm_connector_cleanup(connector);
-       kfree(exynos_connector);
-       return NULL;
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h
deleted file mode 100644 (file)
index 4eb20d7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *     Inki Dae <inki.dae@samsung.com>
- *     Joonyoung Shim <jy0922.shim@samsung.com>
- *     Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DRM_CONNECTOR_H_
-#define _EXYNOS_DRM_CONNECTOR_H_
-
-struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
-                                                  struct drm_encoder *encoder);
-
-#endif
index 48ccab7..eb49195 100644 (file)
@@ -34,9 +34,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
        if (mode > DRM_MODE_DPMS_ON) {
                /* wait for the completion of page flip. */
                if (!wait_event_timeout(exynos_crtc->pending_flip_queue,
-                               !atomic_read(&exynos_crtc->pending_flip),
-                               HZ/20))
-                       atomic_set(&exynos_crtc->pending_flip, 0);
+                               (exynos_crtc->event == NULL), HZ/20))
+                       exynos_crtc->event = NULL;
                drm_crtc_vblank_off(crtc);
        }
 
@@ -164,11 +163,10 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
                                     uint32_t page_flip_flags)
 {
        struct drm_device *dev = crtc->dev;
-       struct exynos_drm_private *dev_priv = dev->dev_private;
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
        struct drm_framebuffer *old_fb = crtc->primary->fb;
        unsigned int crtc_w, crtc_h;
-       int ret = -EINVAL;
+       int ret;
 
        /* when the page flip is requested, crtc's dpms should be on */
        if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
@@ -176,48 +174,49 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
-       mutex_lock(&dev->struct_mutex);
+       if (!event)
+               return -EINVAL;
 
-       if (event) {
-               /*
-                * the pipe from user always is 0 so we can set pipe number
-                * of current owner to event.
-                */
-               event->pipe = exynos_crtc->pipe;
+       spin_lock_irq(&dev->event_lock);
+       if (exynos_crtc->event) {
+               ret = -EBUSY;
+               goto out;
+       }
 
-               ret = drm_vblank_get(dev, exynos_crtc->pipe);
-               if (ret) {
-                       DRM_DEBUG("failed to acquire vblank counter\n");
+       ret = drm_vblank_get(dev, exynos_crtc->pipe);
+       if (ret) {
+               DRM_DEBUG("failed to acquire vblank counter\n");
+               goto out;
+       }
 
-                       goto out;
-               }
+       exynos_crtc->event = event;
+       spin_unlock_irq(&dev->event_lock);
 
+       /*
+        * the pipe from user always is 0 so we can set pipe number
+        * of current owner to event.
+        */
+       event->pipe = exynos_crtc->pipe;
+
+       crtc->primary->fb = fb;
+       crtc_w = fb->width - crtc->x;
+       crtc_h = fb->height - crtc->y;
+       ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0,
+                                 crtc_w, crtc_h, crtc->x, crtc->y,
+                                 crtc_w, crtc_h);
+       if (ret) {
+               crtc->primary->fb = old_fb;
                spin_lock_irq(&dev->event_lock);
-               list_add_tail(&event->base.link,
-                               &dev_priv->pageflip_event_list);
-               atomic_set(&exynos_crtc->pending_flip, 1);
+               exynos_crtc->event = NULL;
+               drm_vblank_put(dev, exynos_crtc->pipe);
                spin_unlock_irq(&dev->event_lock);
-
-               crtc->primary->fb = fb;
-               crtc_w = fb->width - crtc->x;
-               crtc_h = fb->height - crtc->y;
-               ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0,
-                                         crtc_w, crtc_h, crtc->x, crtc->y,
-                                         crtc_w, crtc_h);
-               if (ret) {
-                       crtc->primary->fb = old_fb;
-
-                       spin_lock_irq(&dev->event_lock);
-                       drm_vblank_put(dev, exynos_crtc->pipe);
-                       list_del(&event->base.link);
-                       atomic_set(&exynos_crtc->pending_flip, 0);
-                       spin_unlock_irq(&dev->event_lock);
-
-                       goto out;
-               }
+               return ret;
        }
+
+       return 0;
+
 out:
-       mutex_unlock(&dev->struct_mutex);
+       spin_unlock_irq(&dev->event_lock);
        return ret;
 }
 
@@ -239,13 +238,13 @@ static struct drm_crtc_funcs exynos_crtc_funcs = {
 };
 
 struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
+                                              struct drm_plane *plane,
                                               int pipe,
                                               enum exynos_drm_output_type type,
                                               struct exynos_drm_crtc_ops *ops,
                                               void *ctx)
 {
        struct exynos_drm_crtc *exynos_crtc;
-       struct drm_plane *plane;
        struct exynos_drm_private *private = drm_dev->dev_private;
        struct drm_crtc *crtc;
        int ret;
@@ -255,19 +254,12 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
                return ERR_PTR(-ENOMEM);
 
        init_waitqueue_head(&exynos_crtc->pending_flip_queue);
-       atomic_set(&exynos_crtc->pending_flip, 0);
 
        exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
        exynos_crtc->pipe = pipe;
        exynos_crtc->type = type;
        exynos_crtc->ops = ops;
        exynos_crtc->ctx = ctx;
-       plane = exynos_plane_init(drm_dev, 1 << pipe,
-                                 DRM_PLANE_TYPE_PRIMARY);
-       if (IS_ERR(plane)) {
-               ret = PTR_ERR(plane);
-               goto err_plane;
-       }
 
        crtc = &exynos_crtc->base;
 
@@ -284,7 +276,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
 
 err_crtc:
        plane->funcs->destroy(plane);
-err_plane:
        kfree(exynos_crtc);
        return ERR_PTR(ret);
 }
@@ -320,26 +311,20 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
 {
        struct exynos_drm_private *dev_priv = dev->dev_private;
-       struct drm_pending_vblank_event *e, *t;
        struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
        unsigned long flags;
 
        spin_lock_irqsave(&dev->event_lock, flags);
+       if (exynos_crtc->event) {
 
-       list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
-                       base.link) {
-               /* if event's pipe isn't same as crtc then ignore it. */
-               if (pipe != e->pipe)
-                       continue;
-
-               list_del(&e->base.link);
-               drm_send_vblank_event(dev, -1, e);
+               drm_send_vblank_event(dev, -1, exynos_crtc->event);
                drm_vblank_put(dev, pipe);
-               atomic_set(&exynos_crtc->pending_flip, 0);
                wake_up(&exynos_crtc->pending_flip_queue);
+
        }
 
+       exynos_crtc->event = NULL;
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
index 6258b80..0ecd8fc 100644 (file)
@@ -18,6 +18,7 @@
 #include "exynos_drm_drv.h"
 
 struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
+                                              struct drm_plane *plane,
                                               int pipe,
                                               enum exynos_drm_output_type type,
                                               struct exynos_drm_crtc_ops *ops,
@@ -27,12 +28,6 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
 void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
 
-void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
-                       struct exynos_drm_plane *plane);
-void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
-void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
-void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
-
 /* This function gets pipe value to crtc device matched with out_type. */
 int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
                                        unsigned int out_type);
index 90168d7..8ac4652 100644 (file)
@@ -55,13 +55,11 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 {
        struct exynos_drm_private *private;
        int ret;
-       int nr;
 
        private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
        if (!private)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&private->pageflip_event_list);
        dev_set_drvdata(dev->dev, dev);
        dev->dev_private = (void *)private;
 
@@ -81,19 +79,6 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
        exynos_drm_mode_config_init(dev);
 
-       for (nr = 0; nr < MAX_PLANE; nr++) {
-               struct drm_plane *plane;
-               unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
-
-               plane = exynos_plane_init(dev, possible_crtcs,
-                                         DRM_PLANE_TYPE_OVERLAY);
-               if (!IS_ERR(plane))
-                       continue;
-
-               ret = PTR_ERR(plane);
-               goto err_mode_config_cleanup;
-       }
-
        /* setup possible_clones. */
        exynos_drm_encoder_setup(dev);
 
@@ -237,25 +222,13 @@ 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_pending_vblank_event *v, *vt;
        struct drm_pending_event *e, *et;
        unsigned long flags;
 
        if (!file->driver_priv)
                return;
 
-       /* Release all events not unhandled by page flip handler. */
        spin_lock_irqsave(&dev->event_lock, flags);
-       list_for_each_entry_safe(v, vt, &private->pageflip_event_list,
-                       base.link) {
-               if (v->base.file_priv == file) {
-                       list_del(&v->base.link);
-                       drm_vblank_put(dev, v->pipe);
-                       v->base.destroy(&v->base);
-               }
-       }
-
        /* Release all events handled by page flip handler but not freed. */
        list_for_each_entry_safe(e, et, &file->event_list, link) {
                list_del(&e->link);
index 9afd390..e12ecb5 100644 (file)
@@ -21,7 +21,6 @@
 #define MAX_CRTC       3
 #define MAX_PLANE      5
 #define MAX_FB_BUFFER  4
-#define DEFAULT_ZPOS   -1
 
 #define to_exynos_crtc(x)      container_of(x, struct exynos_drm_crtc, base)
 #define to_exynos_plane(x)     container_of(x, struct exynos_drm_plane, base)
@@ -48,20 +47,22 @@ enum exynos_drm_output_type {
  * Exynos drm common overlay structure.
  *
  * @base: plane object
- * @fb_x: offset x on a framebuffer to be displayed.
+ * @src_x: offset x on a framebuffer to be displayed.
  *     - the unit is screen coordinates.
- * @fb_y: offset y on a framebuffer to be displayed.
+ * @src_y: offset y on a framebuffer to be displayed.
  *     - the unit is screen coordinates.
- * @fb_width: width of a framebuffer.
- * @fb_height: height of a framebuffer.
  * @src_width: width of a partial image to be displayed from framebuffer.
  * @src_height: height of a partial image to be displayed from framebuffer.
+ * @fb_width: width of a framebuffer.
+ * @fb_height: height of a framebuffer.
  * @crtc_x: offset x on hardware screen.
  * @crtc_y: offset y on hardware screen.
  * @crtc_width: window width to be displayed (hardware screen).
  * @crtc_height: window height to be displayed (hardware screen).
  * @mode_width: width of screen mode.
  * @mode_height: height of screen mode.
+ * @h_ratio: horizontal scaling ratio, 16.16 fixed point
+ * @v_ratio: vertical scaling ratio, 16.16 fixed point
  * @refresh: refresh rate.
  * @scan_flag: interlace or progressive way.
  *     (it could be DRM_MODE_FLAG_*)
@@ -78,6 +79,7 @@ enum exynos_drm_output_type {
  * @transparency: transparency on or off.
  * @activated: activated or not.
  * @enabled: enabled or not.
+ * @resume: to resume or not.
  *
  * this structure is common to exynos SoC and its contents would be copied
  * to hardware specific overlay info.
@@ -85,25 +87,27 @@ enum exynos_drm_output_type {
 
 struct exynos_drm_plane {
        struct drm_plane base;
-       unsigned int fb_x;
-       unsigned int fb_y;
-       unsigned int fb_width;
-       unsigned int fb_height;
+       unsigned int src_x;
+       unsigned int src_y;
        unsigned int src_width;
        unsigned int src_height;
+       unsigned int fb_width;
+       unsigned int fb_height;
        unsigned int crtc_x;
        unsigned int crtc_y;
        unsigned int crtc_width;
        unsigned int crtc_height;
        unsigned int mode_width;
        unsigned int mode_height;
+       unsigned int h_ratio;
+       unsigned int v_ratio;
        unsigned int refresh;
        unsigned int scan_flag;
        unsigned int bpp;
        unsigned int pitch;
        uint32_t pixel_format;
        dma_addr_t dma_addr[MAX_FB_BUFFER];
-       int zpos;
+       unsigned int zpos;
        unsigned int index_color;
 
        bool default_win:1;
@@ -112,6 +116,7 @@ struct exynos_drm_plane {
        bool transparency:1;
        bool activated:1;
        bool enabled:1;
+       bool resume:1;
 };
 
 /*
@@ -172,9 +177,7 @@ struct exynos_drm_display {
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
  * @wait_for_vblank: wait for vblank interrupt to make sure that
  *     hardware overlay is updated.
- * @win_mode_set: copy drm overlay info to hw specific overlay info.
  * @win_commit: apply hardware specific overlay data to registers.
- * @win_enable: enable hardware specific overlay.
  * @win_disable: disable hardware specific overlay.
  * @te_handler: trigger to transfer video image at the tearing effect
  *     synchronization signal if there is a page flip request.
@@ -189,11 +192,8 @@ struct exynos_drm_crtc_ops {
        int (*enable_vblank)(struct exynos_drm_crtc *crtc);
        void (*disable_vblank)(struct exynos_drm_crtc *crtc);
        void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
-       void (*win_mode_set)(struct exynos_drm_crtc *crtc,
-                               struct exynos_drm_plane *plane);
-       void (*win_commit)(struct exynos_drm_crtc *crtc, int zpos);
-       void (*win_enable)(struct exynos_drm_crtc *crtc, int zpos);
-       void (*win_disable)(struct exynos_drm_crtc *crtc, int zpos);
+       void (*win_commit)(struct exynos_drm_crtc *crtc, unsigned int zpos);
+       void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos);
        void (*te_handler)(struct exynos_drm_crtc *crtc);
 };
 
@@ -210,6 +210,7 @@ struct exynos_drm_crtc_ops {
  *     we can refer to the crtc to current hardware interrupt occurred through
  *     this pipe value.
  * @dpms: store the crtc dpms value
+ * @event: vblank event that is currently queued for flip
  * @ops: pointer to callbacks for exynos drm specific functionality
  * @ctx: A pointer to the crtc's implementation specific context
  */
@@ -219,7 +220,7 @@ struct exynos_drm_crtc {
        unsigned int                    pipe;
        unsigned int                    dpms;
        wait_queue_head_t               pending_flip_queue;
-       atomic_t                        pending_flip;
+       struct drm_pending_vblank_event *event;
        struct exynos_drm_crtc_ops      *ops;
        void                            *ctx;
 };
@@ -249,9 +250,6 @@ struct drm_exynos_file_private {
 struct exynos_drm_private {
        struct drm_fb_helper *fb_helper;
 
-       /* list head for new event to be added. */
-       struct list_head pageflip_event_list;
-
        /*
         * created crtc object would be contained at this array and
         * this array is used to be aware of which crtc did it request vblank.
index 05fe93d..0492715 100644 (file)
@@ -1473,12 +1473,6 @@ static int exynos_dsi_get_modes(struct drm_connector *connector)
        return 0;
 }
 
-static int exynos_dsi_mode_valid(struct drm_connector *connector,
-                                struct drm_display_mode *mode)
-{
-       return MODE_OK;
-}
-
 static struct drm_encoder *
 exynos_dsi_best_encoder(struct drm_connector *connector)
 {
@@ -1489,7 +1483,6 @@ exynos_dsi_best_encoder(struct drm_connector *connector)
 
 static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
        .get_modes = exynos_dsi_get_modes,
-       .mode_valid = exynos_dsi_mode_valid,
        .best_encoder = exynos_dsi_best_encoder,
 };
 
index d346d1e..929cb03 100644 (file)
@@ -151,10 +151,8 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
        exynos_gem_obj = to_exynos_gem_obj(obj);
 
        ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
-       if (ret < 0) {
-               DRM_ERROR("cannot use this gem memory type for fb.\n");
-               return ERR_PTR(-EINVAL);
-       }
+       if (ret < 0)
+               return ERR_PTR(ret);
 
        exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
        if (!exynos_fb)
@@ -250,10 +248,8 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
                exynos_fb->exynos_gem_obj[i] = exynos_gem_obj;
 
                ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
-               if (ret < 0) {
-                       DRM_ERROR("cannot use this gem memory type for fb.\n");
+               if (ret < 0)
                        goto err_unreference;
-               }
        }
 
        ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
index 925fc69..9819fa6 100644 (file)
@@ -31,7 +31,9 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fbdev.h"
 #include "exynos_drm_crtc.h"
+#include "exynos_drm_plane.h"
 #include "exynos_drm_iommu.h"
+#include "exynos_drm_fimd.h"
 
 /*
  * FIMD stands for Fully Interactive Mobile Display and
@@ -54,6 +56,9 @@
 /* size control register for hardware windows 1 ~ 2. */
 #define VIDOSD_D(win)          (VIDOSD_BASE + 0x0C + (win) * 16)
 
+#define VIDWnALPHA0(win)       (VIDW_ALPHA + 0x00 + (win) * 8)
+#define VIDWnALPHA1(win)       (VIDW_ALPHA + 0x04 + (win) * 8)
+
 #define VIDWx_BUF_START(win, buf)      (VIDW_BUF_START(buf) + (win) * 8)
 #define VIDWx_BUF_END(win, buf)                (VIDW_BUF_END(buf) + (win) * 8)
 #define VIDWx_BUF_SIZE(win, buf)       (VIDW_BUF_SIZE(buf) + (win) * 4)
@@ -140,31 +145,15 @@ static struct fimd_driver_data exynos5_fimd_driver_data = {
        .has_vtsel = 1,
 };
 
-struct fimd_win_data {
-       unsigned int            offset_x;
-       unsigned int            offset_y;
-       unsigned int            ovl_width;
-       unsigned int            ovl_height;
-       unsigned int            fb_width;
-       unsigned int            fb_height;
-       unsigned int            bpp;
-       unsigned int            pixel_format;
-       dma_addr_t              dma_addr;
-       unsigned int            buf_offsize;
-       unsigned int            line_size;      /* bytes */
-       bool                    enabled;
-       bool                    resume;
-};
-
 struct fimd_context {
        struct device                   *dev;
        struct drm_device               *drm_dev;
        struct exynos_drm_crtc          *crtc;
+       struct exynos_drm_plane         planes[WINDOWS_NR];
        struct clk                      *bus_clk;
        struct clk                      *lcd_clk;
        void __iomem                    *regs;
        struct regmap                   *sysreg;
-       struct fimd_win_data            win_data[WINDOWS_NR];
        unsigned int                    default_win;
        unsigned long                   irq_flags;
        u32                             vidcon0;
@@ -284,14 +273,9 @@ static void fimd_clear_channel(struct fimd_context *ctx)
        }
 }
 
-static int fimd_ctx_initialize(struct fimd_context *ctx,
+static int fimd_iommu_attach_devices(struct fimd_context *ctx,
                        struct drm_device *drm_dev)
 {
-       struct exynos_drm_private *priv;
-       priv = drm_dev->dev_private;
-
-       ctx->drm_dev = drm_dev;
-       ctx->pipe = priv->pipe++;
 
        /* attach this sub driver to iommu mapping if supported. */
        if (is_drm_iommu_supported(ctx->drm_dev)) {
@@ -313,7 +297,7 @@ static int fimd_ctx_initialize(struct fimd_context *ctx,
        return 0;
 }
 
-static void fimd_ctx_remove(struct fimd_context *ctx)
+static void fimd_iommu_detach_devices(struct fimd_context *ctx)
 {
        /* detach this sub driver from iommu mapping if supported. */
        if (is_drm_iommu_supported(ctx->drm_dev))
@@ -506,58 +490,9 @@ static void fimd_disable_vblank(struct exynos_drm_crtc *crtc)
        }
 }
 
-static void fimd_win_mode_set(struct exynos_drm_crtc *crtc,
-                       struct exynos_drm_plane *plane)
-{
-       struct fimd_context *ctx = crtc->ctx;
-       struct fimd_win_data *win_data;
-       int win;
-       unsigned long offset;
-
-       if (!plane) {
-               DRM_ERROR("plane is NULL\n");
-               return;
-       }
-
-       win = plane->zpos;
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-       offset = plane->fb_x * (plane->bpp >> 3);
-       offset += plane->fb_y * plane->pitch;
-
-       DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch);
-
-       win_data = &ctx->win_data[win];
-
-       win_data->offset_x = plane->crtc_x;
-       win_data->offset_y = plane->crtc_y;
-       win_data->ovl_width = plane->crtc_width;
-       win_data->ovl_height = plane->crtc_height;
-       win_data->fb_width = plane->fb_width;
-       win_data->fb_height = plane->fb_height;
-       win_data->dma_addr = plane->dma_addr[0] + offset;
-       win_data->bpp = plane->bpp;
-       win_data->pixel_format = plane->pixel_format;
-       win_data->buf_offsize = (plane->fb_width - plane->crtc_width) *
-                               (plane->bpp >> 3);
-       win_data->line_size = plane->crtc_width * (plane->bpp >> 3);
-
-       DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
-                       win_data->offset_x, win_data->offset_y);
-       DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       win_data->ovl_width, win_data->ovl_height);
-       DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
-       DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
-                       plane->fb_width, plane->crtc_width);
-}
-
 static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
 {
-       struct fimd_win_data *win_data = &ctx->win_data[win];
+       struct exynos_drm_plane *plane = &ctx->planes[win];
        unsigned long val;
 
        val = WINCONx_ENWIN;
@@ -567,11 +502,11 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
         * So the request format is ARGB8888 then change it to XRGB8888.
         */
        if (ctx->driver_data->has_limited_fmt && !win) {
-               if (win_data->pixel_format == DRM_FORMAT_ARGB8888)
-                       win_data->pixel_format = DRM_FORMAT_XRGB8888;
+               if (plane->pixel_format == DRM_FORMAT_ARGB8888)
+                       plane->pixel_format = DRM_FORMAT_XRGB8888;
        }
 
-       switch (win_data->pixel_format) {
+       switch (plane->pixel_format) {
        case DRM_FORMAT_C8:
                val |= WINCON0_BPPMODE_8BPP_PALETTE;
                val |= WINCONx_BURSTLEN_8WORD;
@@ -607,7 +542,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
                break;
        }
 
-       DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
+       DRM_DEBUG_KMS("bpp = %d\n", plane->bpp);
 
        /*
         * In case of exynos, setting dma-burst to 16Word causes permanent
@@ -617,12 +552,30 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
         * movement causes unstable DMA which results into iommu crash/tear.
         */
 
-       if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+       if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
                val &= ~WINCONx_BURSTLEN_MASK;
                val |= WINCONx_BURSTLEN_4WORD;
        }
 
        writel(val, ctx->regs + WINCON(win));
+
+       /* hardware window 0 doesn't support alpha channel. */
+       if (win != 0) {
+               /* OSD alpha */
+               val = VIDISD14C_ALPHA0_R(0xf) |
+                       VIDISD14C_ALPHA0_G(0xf) |
+                       VIDISD14C_ALPHA0_B(0xf) |
+                       VIDISD14C_ALPHA1_R(0xf) |
+                       VIDISD14C_ALPHA1_G(0xf) |
+                       VIDISD14C_ALPHA1_B(0xf);
+
+               writel(val, ctx->regs + VIDOSD_C(win));
+
+               val = VIDW_ALPHA_R(0xf) | VIDW_ALPHA_G(0xf) |
+                       VIDW_ALPHA_G(0xf);
+               writel(val, ctx->regs + VIDWnALPHA0(win));
+               writel(val, ctx->regs + VIDWnALPHA1(win));
+       }
 }
 
 static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win)
@@ -645,7 +598,7 @@ static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win)
  * @protect: 1 to protect (disable updates)
  */
 static void fimd_shadow_protect_win(struct fimd_context *ctx,
-                                                       int win, bool protect)
+                                   unsigned int win, bool protect)
 {
        u32 reg, bits, val;
 
@@ -665,29 +618,25 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
        writel(val, ctx->regs + reg);
 }
 
-static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
+static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct fimd_context *ctx = crtc->ctx;
-       struct fimd_win_data *win_data;
-       int win = zpos;
-       unsigned long val, alpha, size;
-       unsigned int last_x;
-       unsigned int last_y;
+       struct exynos_drm_plane *plane;
+       dma_addr_t dma_addr;
+       unsigned long val, size, offset;
+       unsigned int last_x, last_y, buf_offsize, line_size;
 
        if (ctx->suspended)
                return;
 
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
        /* If suspended, enable this on resume */
        if (ctx->suspended) {
-               win_data->resume = true;
+               plane->resume = true;
                return;
        }
 
@@ -704,38 +653,45 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        /* protect windows */
        fimd_shadow_protect_win(ctx, win, true);
 
+
+       offset = plane->src_x * (plane->bpp >> 3);
+       offset += plane->src_y * plane->pitch;
+
        /* buffer start address */
-       val = (unsigned long)win_data->dma_addr;
+       dma_addr = plane->dma_addr[0] + offset;
+       val = (unsigned long)dma_addr;
        writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
 
        /* buffer end address */
-       size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3);
-       val = (unsigned long)(win_data->dma_addr + size);
+       size = plane->pitch * plane->crtc_height;
+       val = (unsigned long)(dma_addr + size);
        writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
 
        DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
-                       (unsigned long)win_data->dma_addr, val, size);
+                       (unsigned long)dma_addr, val, size);
        DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       win_data->ovl_width, win_data->ovl_height);
+                       plane->crtc_width, plane->crtc_height);
 
        /* buffer size */
-       val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) |
-               VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size) |
-               VIDW_BUF_SIZE_OFFSET_E(win_data->buf_offsize) |
-               VIDW_BUF_SIZE_PAGEWIDTH_E(win_data->line_size);
+       buf_offsize = plane->pitch - (plane->crtc_width * (plane->bpp >> 3));
+       line_size = plane->crtc_width * (plane->bpp >> 3);
+       val = VIDW_BUF_SIZE_OFFSET(buf_offsize) |
+               VIDW_BUF_SIZE_PAGEWIDTH(line_size) |
+               VIDW_BUF_SIZE_OFFSET_E(buf_offsize) |
+               VIDW_BUF_SIZE_PAGEWIDTH_E(line_size);
        writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0));
 
        /* OSD position */
-       val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) |
-               VIDOSDxA_TOPLEFT_Y(win_data->offset_y) |
-               VIDOSDxA_TOPLEFT_X_E(win_data->offset_x) |
-               VIDOSDxA_TOPLEFT_Y_E(win_data->offset_y);
+       val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) |
+               VIDOSDxA_TOPLEFT_Y(plane->crtc_y) |
+               VIDOSDxA_TOPLEFT_X_E(plane->crtc_x) |
+               VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y);
        writel(val, ctx->regs + VIDOSD_A(win));
 
-       last_x = win_data->offset_x + win_data->ovl_width;
+       last_x = plane->crtc_x + plane->crtc_width;
        if (last_x)
                last_x--;
-       last_y = win_data->offset_y + win_data->ovl_height;
+       last_y = plane->crtc_y + plane->crtc_height;
        if (last_y)
                last_y--;
 
@@ -745,24 +701,14 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        writel(val, ctx->regs + VIDOSD_B(win));
 
        DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
-                       win_data->offset_x, win_data->offset_y, last_x, last_y);
-
-       /* hardware window 0 doesn't support alpha channel. */
-       if (win != 0) {
-               /* OSD alpha */
-               alpha = VIDISD14C_ALPHA1_R(0xf) |
-                       VIDISD14C_ALPHA1_G(0xf) |
-                       VIDISD14C_ALPHA1_B(0xf);
-
-               writel(alpha, ctx->regs + VIDOSD_C(win));
-       }
+                       plane->crtc_x, plane->crtc_y, last_x, last_y);
 
        /* OSD size */
        if (win != 3 && win != 4) {
                u32 offset = VIDOSD_D(win);
                if (win == 0)
                        offset = VIDOSD_C(win);
-               val = win_data->ovl_width * win_data->ovl_height;
+               val = plane->crtc_width * plane->crtc_height;
                writel(val, ctx->regs + offset);
 
                DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
@@ -782,29 +728,25 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        /* Enable DMA channel and unprotect windows */
        fimd_shadow_protect_win(ctx, win, false);
 
-       win_data->enabled = true;
+       plane->enabled = true;
 
        if (ctx->i80_if)
                atomic_set(&ctx->win_updated, 1);
 }
 
-static void fimd_win_disable(struct exynos_drm_crtc *crtc, int zpos)
+static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct fimd_context *ctx = crtc->ctx;
-       struct fimd_win_data *win_data;
-       int win = zpos;
-
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+       struct exynos_drm_plane *plane;
 
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
        if (ctx->suspended) {
                /* do not resume this window*/
-               win_data->resume = false;
+               plane->resume = false;
                return;
        }
 
@@ -819,42 +761,42 @@ static void fimd_win_disable(struct exynos_drm_crtc *crtc, int zpos)
        /* unprotect windows */
        fimd_shadow_protect_win(ctx, win, false);
 
-       win_data->enabled = false;
+       plane->enabled = false;
 }
 
 static void fimd_window_suspend(struct fimd_context *ctx)
 {
-       struct fimd_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->resume = win_data->enabled;
-               if (win_data->enabled)
+               plane = &ctx->planes[i];
+               plane->resume = plane->enabled;
+               if (plane->enabled)
                        fimd_win_disable(ctx->crtc, i);
        }
 }
 
 static void fimd_window_resume(struct fimd_context *ctx)
 {
-       struct fimd_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->enabled = win_data->resume;
-               win_data->resume = false;
+               plane = &ctx->planes[i];
+               plane->enabled = plane->resume;
+               plane->resume = false;
        }
 }
 
 static void fimd_apply(struct fimd_context *ctx)
 {
-       struct fimd_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               if (win_data->enabled)
+               plane = &ctx->planes[i];
+               if (plane->enabled)
                        fimd_win_commit(ctx->crtc, i);
                else
                        fimd_win_disable(ctx->crtc, i);
@@ -1011,7 +953,6 @@ static struct exynos_drm_crtc_ops fimd_crtc_ops = {
        .enable_vblank = fimd_enable_vblank,
        .disable_vblank = fimd_disable_vblank,
        .wait_for_vblank = fimd_wait_for_vblank,
-       .win_mode_set = fimd_win_mode_set,
        .win_commit = fimd_win_commit,
        .win_disable = fimd_win_disable,
        .te_handler = fimd_te_handler,
@@ -1056,25 +997,38 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
 {
        struct fimd_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
+       struct exynos_drm_private *priv = drm_dev->dev_private;
+       struct exynos_drm_plane *exynos_plane;
+       enum drm_plane_type type;
+       unsigned int zpos;
        int ret;
 
-       ret = fimd_ctx_initialize(ctx, drm_dev);
-       if (ret) {
-               DRM_ERROR("fimd_ctx_initialize failed.\n");
-               return ret;
+       ctx->drm_dev = drm_dev;
+       ctx->pipe = priv->pipe++;
+
+       for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
+               type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
+                                               DRM_PLANE_TYPE_OVERLAY;
+               ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
+                                       1 << ctx->pipe, type, zpos);
+               if (ret)
+                       return ret;
        }
 
-       ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
-                                          EXYNOS_DISPLAY_TYPE_LCD,
+       exynos_plane = &ctx->planes[ctx->default_win];
+       ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
+                                          ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
                                           &fimd_crtc_ops, ctx);
-       if (IS_ERR(ctx->crtc)) {
-               fimd_ctx_remove(ctx);
+       if (IS_ERR(ctx->crtc))
                return PTR_ERR(ctx->crtc);
-       }
 
        if (ctx->display)
                exynos_drm_create_enc_conn(drm_dev, ctx->display);
 
+       ret = fimd_iommu_attach_devices(ctx, drm_dev);
+       if (ret)
+               return ret;
+
        return 0;
 
 }
@@ -1086,10 +1040,10 @@ static void fimd_unbind(struct device *dev, struct device *master,
 
        fimd_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
 
+       fimd_iommu_detach_devices(ctx);
+
        if (ctx->display)
                exynos_dpi_remove(ctx->display);
-
-       fimd_ctx_remove(ctx);
 }
 
 static const struct component_ops fimd_component_ops = {
@@ -1238,6 +1192,24 @@ static int fimd_remove(struct platform_device *pdev)
        return 0;
 }
 
+void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable)
+{
+       struct fimd_context *ctx = crtc->ctx;
+       u32 val;
+
+       /*
+        * Only Exynos 5250, 5260, 5410 and 542x requires enabling DP/MIE
+        * clock. On these SoCs the bootloader may enable it but any
+        * power domain off/on will reset it to disable state.
+        */
+       if (ctx->driver_data != &exynos5_fimd_driver_data)
+               return;
+
+       val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
+       writel(DP_MIE_CLK_DP_ENABLE, ctx->regs + DP_MIE_CLKCON);
+}
+EXPORT_SYMBOL_GPL(fimd_dp_clock_enable);
+
 struct platform_driver fimd_driver = {
        .probe          = fimd_probe,
        .remove         = fimd_remove,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.h b/drivers/gpu/drm/exynos/exynos_drm_fimd.h
new file mode 100644 (file)
index 0000000..b4fcaa5
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2015 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 as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _EXYNOS_DRM_FIMD_H_
+#define _EXYNOS_DRM_FIMD_H_
+
+extern void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable);
+
+#endif /* _EXYNOS_DRM_FIMD_H_ */
index d5ad17d..b7f1cbc 100644 (file)
@@ -476,6 +476,45 @@ err_clear:
        return ret;
 }
 
+static int ipp_validate_mem_node(struct drm_device *drm_dev,
+                                struct drm_exynos_ipp_mem_node *m_node,
+                                struct drm_exynos_ipp_cmd_node *c_node)
+{
+       struct drm_exynos_ipp_config *ipp_cfg;
+       unsigned int num_plane;
+       unsigned long min_size, size;
+       unsigned int bpp;
+       int i;
+
+       /* The property id should already be varified */
+       ipp_cfg = &c_node->property.config[m_node->prop_id];
+       num_plane = drm_format_num_planes(ipp_cfg->fmt);
+
+       /**
+        * This is a rather simplified validation of a memory node.
+        * It basically verifies provided gem object handles
+        * and the buffer sizes with respect to current configuration.
+        * This is not the best that can be done
+        * but it seems more than enough
+        */
+       for (i = 0; i < num_plane; ++i) {
+               if (!m_node->buf_info.handles[i]) {
+                       DRM_ERROR("invalid handle for plane %d\n", i);
+                       return -EINVAL;
+               }
+               bpp = drm_format_plane_cpp(ipp_cfg->fmt, i);
+               min_size = (ipp_cfg->sz.hsize * ipp_cfg->sz.vsize * bpp) >> 3;
+               size = exynos_drm_gem_get_size(drm_dev,
+                                              m_node->buf_info.handles[i],
+                                              c_node->filp);
+               if (min_size > size) {
+                       DRM_ERROR("invalid size for plane %d\n", i);
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
 static int ipp_put_mem_node(struct drm_device *drm_dev,
                struct drm_exynos_ipp_cmd_node *c_node,
                struct drm_exynos_ipp_mem_node *m_node)
@@ -552,6 +591,11 @@ static struct drm_exynos_ipp_mem_node
        }
 
        mutex_lock(&c_node->mem_lock);
+       if (ipp_validate_mem_node(drm_dev, m_node, c_node)) {
+               ipp_put_mem_node(drm_dev, c_node, m_node);
+               mutex_unlock(&c_node->mem_lock);
+               return ERR_PTR(-EFAULT);
+       }
        list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]);
        mutex_unlock(&c_node->mem_lock);
 
index a561687..13ea334 100644 (file)
@@ -92,7 +92,6 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                          uint32_t src_w, uint32_t src_h)
 {
        struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
-       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
        unsigned int actual_w;
        unsigned int actual_h;
 
@@ -111,13 +110,17 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                crtc_y = 0;
        }
 
+       /* set ratio */
+       exynos_plane->h_ratio = (src_w << 16) / crtc_w;
+       exynos_plane->v_ratio = (src_h << 16) / crtc_h;
+
        /* set drm framebuffer data. */
-       exynos_plane->fb_x = src_x;
-       exynos_plane->fb_y = src_y;
+       exynos_plane->src_x = src_x;
+       exynos_plane->src_y = src_y;
+       exynos_plane->src_width = (actual_w * exynos_plane->h_ratio) >> 16;
+       exynos_plane->src_height = (actual_h * exynos_plane->v_ratio) >> 16;
        exynos_plane->fb_width = fb->width;
        exynos_plane->fb_height = fb->height;
-       exynos_plane->src_width = src_w;
-       exynos_plane->src_height = src_h;
        exynos_plane->bpp = fb->bits_per_pixel;
        exynos_plane->pitch = fb->pitches[0];
        exynos_plane->pixel_format = fb->pixel_format;
@@ -139,9 +142,6 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                        exynos_plane->crtc_width, exynos_plane->crtc_height);
 
        plane->crtc = crtc;
-
-       if (exynos_crtc->ops->win_mode_set)
-               exynos_crtc->ops->win_mode_set(exynos_crtc, exynos_plane);
 }
 
 int
@@ -175,46 +175,21 @@ static int exynos_disable_plane(struct drm_plane *plane)
        struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc);
 
-       if (exynos_crtc->ops->win_disable)
+       if (exynos_crtc && exynos_crtc->ops->win_disable)
                exynos_crtc->ops->win_disable(exynos_crtc,
                                              exynos_plane->zpos);
 
        return 0;
 }
 
-static void exynos_plane_destroy(struct drm_plane *plane)
-{
-       struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
-
-       exynos_disable_plane(plane);
-       drm_plane_cleanup(plane);
-       kfree(exynos_plane);
-}
-
-static int exynos_plane_set_property(struct drm_plane *plane,
-                                    struct drm_property *property,
-                                    uint64_t val)
-{
-       struct drm_device *dev = plane->dev;
-       struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
-       struct exynos_drm_private *dev_priv = dev->dev_private;
-
-       if (property == dev_priv->plane_zpos_property) {
-               exynos_plane->zpos = val;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
 static struct drm_plane_funcs exynos_plane_funcs = {
        .update_plane   = exynos_update_plane,
        .disable_plane  = exynos_disable_plane,
-       .destroy        = exynos_plane_destroy,
-       .set_property   = exynos_plane_set_property,
+       .destroy        = drm_plane_cleanup,
 };
 
-static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
+static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
+                                             unsigned int zpos)
 {
        struct drm_device *dev = plane->dev;
        struct exynos_drm_private *dev_priv = dev->dev_private;
@@ -222,41 +197,36 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
 
        prop = dev_priv->plane_zpos_property;
        if (!prop) {
-               prop = drm_property_create_range(dev, 0, "zpos", 0,
-                                                MAX_PLANE - 1);
+               prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE,
+                                                "zpos", 0, MAX_PLANE - 1);
                if (!prop)
                        return;
 
                dev_priv->plane_zpos_property = prop;
        }
 
-       drm_object_attach_property(&plane->base, prop, 0);
+       drm_object_attach_property(&plane->base, prop, zpos);
 }
 
-struct drm_plane *exynos_plane_init(struct drm_device *dev,
-                                   unsigned long possible_crtcs,
-                                   enum drm_plane_type type)
+int exynos_plane_init(struct drm_device *dev,
+                     struct exynos_drm_plane *exynos_plane,
+                     unsigned long possible_crtcs, enum drm_plane_type type,
+                     unsigned int zpos)
 {
-       struct exynos_drm_plane *exynos_plane;
        int err;
 
-       exynos_plane = kzalloc(sizeof(struct exynos_drm_plane), GFP_KERNEL);
-       if (!exynos_plane)
-               return ERR_PTR(-ENOMEM);
-
        err = drm_universal_plane_init(dev, &exynos_plane->base, possible_crtcs,
                                       &exynos_plane_funcs, formats,
                                       ARRAY_SIZE(formats), type);
        if (err) {
                DRM_ERROR("failed to initialize plane\n");
-               kfree(exynos_plane);
-               return ERR_PTR(err);
+               return err;
        }
 
-       if (type == DRM_PLANE_TYPE_PRIMARY)
-               exynos_plane->zpos = DEFAULT_ZPOS;
-       else
-               exynos_plane_attach_zpos_property(&exynos_plane->base);
+       exynos_plane->zpos = zpos;
 
-       return &exynos_plane->base;
+       if (type == DRM_PLANE_TYPE_OVERLAY)
+               exynos_plane_attach_zpos_property(&exynos_plane->base, zpos);
+
+       return 0;
 }
index 9d3c374..f360590 100644 (file)
@@ -20,6 +20,7 @@ int exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                        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 drm_plane *exynos_plane_init(struct drm_device *dev,
-                                   unsigned long possible_crtcs,
-                                   enum drm_plane_type type);
+int exynos_plane_init(struct drm_device *dev,
+                     struct exynos_drm_plane *exynos_plane,
+                     unsigned long possible_crtcs, enum drm_plane_type type,
+                     unsigned int zpos);
index b886972..27e84ec 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
+#include "exynos_drm_plane.h"
 #include "exynos_drm_encoder.h"
 #include "exynos_drm_vidi.h"
 
 #define ctx_from_connector(c)  container_of(c, struct vidi_context, \
                                        connector)
 
-struct vidi_win_data {
-       unsigned int            offset_x;
-       unsigned int            offset_y;
-       unsigned int            ovl_width;
-       unsigned int            ovl_height;
-       unsigned int            fb_width;
-       unsigned int            fb_height;
-       unsigned int            bpp;
-       dma_addr_t              dma_addr;
-       unsigned int            buf_offsize;
-       unsigned int            line_size;      /* bytes */
-       bool                    enabled;
-};
-
 struct vidi_context {
        struct exynos_drm_display       display;
        struct platform_device          *pdev;
@@ -53,7 +40,7 @@ struct vidi_context {
        struct exynos_drm_crtc          *crtc;
        struct drm_encoder              *encoder;
        struct drm_connector            connector;
-       struct vidi_win_data            win_data[WINDOWS_NR];
+       struct exynos_drm_plane         planes[WINDOWS_NR];
        struct edid                     *raw_edid;
        unsigned int                    clkdiv;
        unsigned int                    default_win;
@@ -97,19 +84,6 @@ static const char fake_edid_info[] = {
        0x00, 0x00, 0x00, 0x06
 };
 
-static void vidi_apply(struct vidi_context *ctx)
-{
-       struct exynos_drm_crtc_ops *crtc_ops = ctx->crtc->ops;
-       struct vidi_win_data *win_data;
-       int i;
-
-       for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               if (win_data->enabled && (crtc_ops && crtc_ops->win_commit))
-                       crtc_ops->win_commit(ctx->crtc, i);
-       }
-}
-
 static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
 {
        struct vidi_context *ctx = crtc->ctx;
@@ -143,104 +117,46 @@ static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
                ctx->vblank_on = false;
 }
 
-static void vidi_win_mode_set(struct exynos_drm_crtc *crtc,
-                       struct exynos_drm_plane *plane)
-{
-       struct vidi_context *ctx = crtc->ctx;
-       struct vidi_win_data *win_data;
-       int win;
-       unsigned long offset;
-
-       if (!plane) {
-               DRM_ERROR("plane is NULL\n");
-               return;
-       }
-
-       win = plane->zpos;
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-       offset = plane->fb_x * (plane->bpp >> 3);
-       offset += plane->fb_y * plane->pitch;
-
-       DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch);
-
-       win_data = &ctx->win_data[win];
-
-       win_data->offset_x = plane->crtc_x;
-       win_data->offset_y = plane->crtc_y;
-       win_data->ovl_width = plane->crtc_width;
-       win_data->ovl_height = plane->crtc_height;
-       win_data->fb_width = plane->fb_width;
-       win_data->fb_height = plane->fb_height;
-       win_data->dma_addr = plane->dma_addr[0] + offset;
-       win_data->bpp = plane->bpp;
-       win_data->buf_offsize = (plane->fb_width - plane->crtc_width) *
-                               (plane->bpp >> 3);
-       win_data->line_size = plane->crtc_width * (plane->bpp >> 3);
-
-       /*
-        * some parts of win_data should be transferred to user side
-        * through specific ioctl.
-        */
-
-       DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
-                       win_data->offset_x, win_data->offset_y);
-       DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       win_data->ovl_width, win_data->ovl_height);
-       DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
-       DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
-                       plane->fb_width, plane->crtc_width);
-}
-
-static void vidi_win_commit(struct exynos_drm_crtc *crtc, int zpos)
+static void vidi_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct vidi_context *ctx = crtc->ctx;
-       struct vidi_win_data *win_data;
-       int win = zpos;
+       struct exynos_drm_plane *plane;
 
        if (ctx->suspended)
                return;
 
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
-       win_data->enabled = true;
+       plane->enabled = true;
 
-       DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
+       DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr);
 
        if (ctx->vblank_on)
                schedule_work(&ctx->work);
 }
 
-static void vidi_win_disable(struct exynos_drm_crtc *crtc, int zpos)
+static void vidi_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct vidi_context *ctx = crtc->ctx;
-       struct vidi_win_data *win_data;
-       int win = zpos;
-
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+       struct exynos_drm_plane *plane;
 
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
-       win_data->enabled = false;
+       plane = &ctx->planes[win];
+       plane->enabled = false;
 
        /* TODO. */
 }
 
 static int vidi_power_on(struct vidi_context *ctx, bool enable)
 {
+       struct exynos_drm_plane *plane;
+       int i;
+
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        if (enable != false && enable != true)
@@ -253,7 +169,11 @@ static int vidi_power_on(struct vidi_context *ctx, bool enable)
                if (test_and_clear_bit(0, &ctx->irq_flags))
                        vidi_enable_vblank(ctx->crtc);
 
-               vidi_apply(ctx);
+               for (i = 0; i < WINDOWS_NR; i++) {
+                       plane = &ctx->planes[i];
+                       if (plane->enabled)
+                               vidi_win_commit(ctx->crtc, i);
+               }
        } else {
                ctx->suspended = true;
        }
@@ -301,7 +221,6 @@ static struct exynos_drm_crtc_ops vidi_crtc_ops = {
        .dpms = vidi_dpms,
        .enable_vblank = vidi_enable_vblank,
        .disable_vblank = vidi_disable_vblank,
-       .win_mode_set = vidi_win_mode_set,
        .win_commit = vidi_win_commit,
        .win_disable = vidi_win_disable,
 };
@@ -543,12 +462,25 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
 {
        struct vidi_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
+       struct exynos_drm_plane *exynos_plane;
+       enum drm_plane_type type;
+       unsigned int zpos;
        int ret;
 
        vidi_ctx_initialize(ctx, drm_dev);
 
-       ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
-                                          EXYNOS_DISPLAY_TYPE_VIDI,
+       for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
+               type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
+                                               DRM_PLANE_TYPE_OVERLAY;
+               ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
+                                       1 << ctx->pipe, type, zpos);
+               if (ret)
+                       return ret;
+       }
+
+       exynos_plane = &ctx->planes[ctx->default_win];
+       ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
+                                          ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI,
                                           &vidi_crtc_ops, ctx);
        if (IS_ERR(ctx->crtc)) {
                DRM_ERROR("failed to create crtc.\n");
index 229b361..722cbf3 100644 (file)
@@ -2007,7 +2007,7 @@ static void hdmi_mode_set(struct exynos_drm_display *display,
        DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
                m->hdisplay, m->vdisplay,
                m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
-               "INTERLACED" : "PROGERESSIVE");
+               "INTERLACED" : "PROGRESSIVE");
 
        /* preserve mode information for later use. */
        drm_mode_copy(&hdata->current_mode, mode);
index 3518bc4..fbec750 100644 (file)
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
+#include "exynos_drm_plane.h"
 #include "exynos_drm_iommu.h"
 #include "exynos_mixer.h"
 
 #define MIXER_WIN_NR           3
 #define MIXER_DEFAULT_WIN      0
 
-struct hdmi_win_data {
-       dma_addr_t              dma_addr;
-       dma_addr_t              chroma_dma_addr;
-       uint32_t                pixel_format;
-       unsigned int            bpp;
-       unsigned int            crtc_x;
-       unsigned int            crtc_y;
-       unsigned int            crtc_width;
-       unsigned int            crtc_height;
-       unsigned int            fb_x;
-       unsigned int            fb_y;
-       unsigned int            fb_width;
-       unsigned int            fb_height;
-       unsigned int            src_width;
-       unsigned int            src_height;
-       unsigned int            mode_width;
-       unsigned int            mode_height;
-       unsigned int            scan_flags;
-       bool                    enabled;
-       bool                    resume;
-};
-
 struct mixer_resources {
        int                     irq;
        void __iomem            *mixer_regs;
@@ -89,6 +68,7 @@ struct mixer_context {
        struct device           *dev;
        struct drm_device       *drm_dev;
        struct exynos_drm_crtc  *crtc;
+       struct exynos_drm_plane planes[MIXER_WIN_NR];
        int                     pipe;
        bool                    interlace;
        bool                    powered;
@@ -98,7 +78,6 @@ struct mixer_context {
 
        struct mutex            mixer_mutex;
        struct mixer_resources  mixer_res;
-       struct hdmi_win_data    win_data[MIXER_WIN_NR];
        enum mixer_version_id   mxr_ver;
        wait_queue_head_t       wait_vsync_queue;
        atomic_t                wait_vsync_event;
@@ -288,7 +267,7 @@ static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
 
        /* choosing between interlace and progressive mode */
        val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
-                               MXR_CFG_SCAN_PROGRASSIVE);
+                               MXR_CFG_SCAN_PROGRESSIVE);
 
        if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
                /* choosing between proper HD and SD mode */
@@ -402,17 +381,16 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
 {
        struct mixer_resources *res = &ctx->mixer_res;
        unsigned long flags;
-       struct hdmi_win_data *win_data;
-       unsigned int x_ratio, y_ratio;
+       struct exynos_drm_plane *plane;
        unsigned int buf_num = 1;
        dma_addr_t luma_addr[2], chroma_addr[2];
        bool tiled_mode = false;
        bool crcb_mode = false;
        u32 val;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
-       switch (win_data->pixel_format) {
+       switch (plane->pixel_format) {
        case DRM_FORMAT_NV12:
                crcb_mode = false;
                buf_num = 2;
@@ -420,35 +398,31 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
        /* TODO: single buffer format NV12, NV21 */
        default:
                /* ignore pixel format at disable time */
-               if (!win_data->dma_addr)
+               if (!plane->dma_addr[0])
                        break;
 
                DRM_ERROR("pixel format for vp is wrong [%d].\n",
-                               win_data->pixel_format);
+                               plane->pixel_format);
                return;
        }
 
-       /* scaling feature: (src << 16) / dst */
-       x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
-       y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
-
        if (buf_num == 2) {
-               luma_addr[0] = win_data->dma_addr;
-               chroma_addr[0] = win_data->chroma_dma_addr;
+               luma_addr[0] = plane->dma_addr[0];
+               chroma_addr[0] = plane->dma_addr[1];
        } else {
-               luma_addr[0] = win_data->dma_addr;
-               chroma_addr[0] = win_data->dma_addr
-                       + (win_data->fb_width * win_data->fb_height);
+               luma_addr[0] = plane->dma_addr[0];
+               chroma_addr[0] = plane->dma_addr[0]
+                       + (plane->pitch * plane->fb_height);
        }
 
-       if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
+       if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
                ctx->interlace = true;
                if (tiled_mode) {
                        luma_addr[1] = luma_addr[0] + 0x40;
                        chroma_addr[1] = chroma_addr[0] + 0x40;
                } else {
-                       luma_addr[1] = luma_addr[0] + win_data->fb_width;
-                       chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
+                       luma_addr[1] = luma_addr[0] + plane->pitch;
+                       chroma_addr[1] = chroma_addr[0] + plane->pitch;
                }
        } else {
                ctx->interlace = false;
@@ -469,30 +443,30 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
        vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
 
        /* setting size of input image */
-       vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
-               VP_IMG_VSIZE(win_data->fb_height));
+       vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) |
+               VP_IMG_VSIZE(plane->fb_height));
        /* chroma height has to reduced by 2 to avoid chroma distorions */
-       vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
-               VP_IMG_VSIZE(win_data->fb_height / 2));
+       vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) |
+               VP_IMG_VSIZE(plane->fb_height / 2));
 
-       vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
-       vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
+       vp_reg_write(res, VP_SRC_WIDTH, plane->src_width);
+       vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height);
        vp_reg_write(res, VP_SRC_H_POSITION,
-                       VP_SRC_H_POSITION_VAL(win_data->fb_x));
-       vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
+                       VP_SRC_H_POSITION_VAL(plane->src_x));
+       vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y);
 
-       vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
-       vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
+       vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width);
+       vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
        if (ctx->interlace) {
-               vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
-               vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
+               vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
+               vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
        } else {
-               vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
-               vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
+               vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
+               vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
        }
 
-       vp_reg_write(res, VP_H_RATIO, x_ratio);
-       vp_reg_write(res, VP_V_RATIO, y_ratio);
+       vp_reg_write(res, VP_H_RATIO, plane->h_ratio);
+       vp_reg_write(res, VP_V_RATIO, plane->v_ratio);
 
        vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
 
@@ -502,8 +476,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
        vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
        vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
 
-       mixer_cfg_scan(ctx, win_data->mode_height);
-       mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
+       mixer_cfg_scan(ctx, plane->mode_height);
+       mixer_cfg_rgb_fmt(ctx, plane->mode_height);
        mixer_cfg_layer(ctx, win, true);
        mixer_run(ctx);
 
@@ -520,25 +494,49 @@ static void mixer_layer_update(struct mixer_context *ctx)
        mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
 }
 
+static int mixer_setup_scale(const struct exynos_drm_plane *plane,
+               unsigned int *x_ratio, unsigned int *y_ratio)
+{
+       if (plane->crtc_width != plane->src_width) {
+               if (plane->crtc_width == 2 * plane->src_width)
+                       *x_ratio = 1;
+               else
+                       goto fail;
+       }
+
+       if (plane->crtc_height != plane->src_height) {
+               if (plane->crtc_height == 2 * plane->src_height)
+                       *y_ratio = 1;
+               else
+                       goto fail;
+       }
+
+       return 0;
+
+fail:
+       DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n");
+       return -ENOTSUPP;
+}
+
 static void mixer_graph_buffer(struct mixer_context *ctx, int win)
 {
        struct mixer_resources *res = &ctx->mixer_res;
        unsigned long flags;
-       struct hdmi_win_data *win_data;
-       unsigned int x_ratio, y_ratio;
+       struct exynos_drm_plane *plane;
+       unsigned int x_ratio = 0, y_ratio = 0;
        unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
        dma_addr_t dma_addr;
        unsigned int fmt;
        u32 val;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
        #define RGB565 4
        #define ARGB1555 5
        #define ARGB4444 6
        #define ARGB8888 7
 
-       switch (win_data->bpp) {
+       switch (plane->bpp) {
        case 16:
                fmt = ARGB4444;
                break;
@@ -549,21 +547,21 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
                fmt = ARGB8888;
        }
 
-       /* 2x scaling feature */
-       x_ratio = 0;
-       y_ratio = 0;
+       /* check if mixer supports requested scaling setup */
+       if (mixer_setup_scale(plane, &x_ratio, &y_ratio))
+               return;
 
-       dst_x_offset = win_data->crtc_x;
-       dst_y_offset = win_data->crtc_y;
+       dst_x_offset = plane->crtc_x;
+       dst_y_offset = plane->crtc_y;
 
        /* converting dma address base and source offset */
-       dma_addr = win_data->dma_addr
-               + (win_data->fb_x * win_data->bpp >> 3)
-               + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
+       dma_addr = plane->dma_addr[0]
+               + (plane->src_x * plane->bpp >> 3)
+               + (plane->src_y * plane->pitch);
        src_x_offset = 0;
        src_y_offset = 0;
 
-       if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
+       if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
                ctx->interlace = true;
        else
                ctx->interlace = false;
@@ -576,18 +574,19 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
                MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
 
        /* setup geometry */
-       mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
+       mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
+                       plane->pitch / (plane->bpp >> 3));
 
        /* setup display size */
        if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
                win == MIXER_DEFAULT_WIN) {
-               val  = MXR_MXR_RES_HEIGHT(win_data->mode_height);
-               val |= MXR_MXR_RES_WIDTH(win_data->mode_width);
+               val  = MXR_MXR_RES_HEIGHT(plane->mode_height);
+               val |= MXR_MXR_RES_WIDTH(plane->mode_width);
                mixer_reg_write(res, MXR_RESOLUTION, val);
        }
 
-       val  = MXR_GRP_WH_WIDTH(win_data->crtc_width);
-       val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
+       val  = MXR_GRP_WH_WIDTH(plane->src_width);
+       val |= MXR_GRP_WH_HEIGHT(plane->src_height);
        val |= MXR_GRP_WH_H_SCALE(x_ratio);
        val |= MXR_GRP_WH_V_SCALE(y_ratio);
        mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
@@ -605,8 +604,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
        /* set buffer address to mixer */
        mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
 
-       mixer_cfg_scan(ctx, win_data->mode_height);
-       mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
+       mixer_cfg_scan(ctx, plane->mode_height);
+       mixer_cfg_rgb_fmt(ctx, plane->mode_height);
        mixer_cfg_layer(ctx, win, true);
 
        /* layer update mandatory for mixer 16.0.33.0 */
@@ -918,62 +917,9 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
        mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
-static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
-                       struct exynos_drm_plane *plane)
-{
-       struct mixer_context *mixer_ctx = crtc->ctx;
-       struct hdmi_win_data *win_data;
-       int win;
-
-       if (!plane) {
-               DRM_ERROR("plane is NULL\n");
-               return;
-       }
-
-       DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
-                                plane->fb_width, plane->fb_height,
-                                plane->fb_x, plane->fb_y,
-                                plane->crtc_width, plane->crtc_height,
-                                plane->crtc_x, plane->crtc_y);
-
-       win = plane->zpos;
-       if (win == DEFAULT_ZPOS)
-               win = MIXER_DEFAULT_WIN;
-
-       if (win < 0 || win >= MIXER_WIN_NR) {
-               DRM_ERROR("mixer window[%d] is wrong\n", win);
-               return;
-       }
-
-       win_data = &mixer_ctx->win_data[win];
-
-       win_data->dma_addr = plane->dma_addr[0];
-       win_data->chroma_dma_addr = plane->dma_addr[1];
-       win_data->pixel_format = plane->pixel_format;
-       win_data->bpp = plane->bpp;
-
-       win_data->crtc_x = plane->crtc_x;
-       win_data->crtc_y = plane->crtc_y;
-       win_data->crtc_width = plane->crtc_width;
-       win_data->crtc_height = plane->crtc_height;
-
-       win_data->fb_x = plane->fb_x;
-       win_data->fb_y = plane->fb_y;
-       win_data->fb_width = plane->fb_width;
-       win_data->fb_height = plane->fb_height;
-       win_data->src_width = plane->src_width;
-       win_data->src_height = plane->src_height;
-
-       win_data->mode_width = plane->mode_width;
-       win_data->mode_height = plane->mode_height;
-
-       win_data->scan_flags = plane->scan_flag;
-}
-
-static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
+static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct mixer_context *mixer_ctx = crtc->ctx;
-       int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
 
        DRM_DEBUG_KMS("win: %d\n", win);
 
@@ -989,14 +935,13 @@ static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        else
                mixer_graph_buffer(mixer_ctx, win);
 
-       mixer_ctx->win_data[win].enabled = true;
+       mixer_ctx->planes[win].enabled = true;
 }
 
-static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
+static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct mixer_context *mixer_ctx = crtc->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
-       int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
        unsigned long flags;
 
        DRM_DEBUG_KMS("win: %d\n", win);
@@ -1004,7 +949,7 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
        mutex_lock(&mixer_ctx->mixer_mutex);
        if (!mixer_ctx->powered) {
                mutex_unlock(&mixer_ctx->mixer_mutex);
-               mixer_ctx->win_data[win].resume = false;
+               mixer_ctx->planes[win].resume = false;
                return;
        }
        mutex_unlock(&mixer_ctx->mixer_mutex);
@@ -1017,7 +962,7 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
        mixer_vsync_set_update(mixer_ctx, true);
        spin_unlock_irqrestore(&res->reg_slock, flags);
 
-       mixer_ctx->win_data[win].enabled = false;
+       mixer_ctx->planes[win].enabled = false;
 }
 
 static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
@@ -1054,12 +999,12 @@ static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
 
 static void mixer_window_suspend(struct mixer_context *ctx)
 {
-       struct hdmi_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < MIXER_WIN_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->resume = win_data->enabled;
+               plane = &ctx->planes[i];
+               plane->resume = plane->enabled;
                mixer_win_disable(ctx->crtc, i);
        }
        mixer_wait_for_vblank(ctx->crtc);
@@ -1067,14 +1012,14 @@ static void mixer_window_suspend(struct mixer_context *ctx)
 
 static void mixer_window_resume(struct mixer_context *ctx)
 {
-       struct hdmi_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < MIXER_WIN_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->enabled = win_data->resume;
-               win_data->resume = false;
-               if (win_data->enabled)
+               plane = &ctx->planes[i];
+               plane->enabled = plane->resume;
+               plane->resume = false;
+               if (plane->enabled)
                        mixer_win_commit(ctx->crtc, i);
        }
 }
@@ -1186,7 +1131,6 @@ static struct exynos_drm_crtc_ops mixer_crtc_ops = {
        .enable_vblank          = mixer_enable_vblank,
        .disable_vblank         = mixer_disable_vblank,
        .wait_for_vblank        = mixer_wait_for_vblank,
-       .win_mode_set           = mixer_win_mode_set,
        .win_commit             = mixer_win_commit,
        .win_disable            = mixer_win_disable,
 };
@@ -1250,15 +1194,28 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
 {
        struct mixer_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
+       struct exynos_drm_plane *exynos_plane;
+       enum drm_plane_type type;
+       unsigned int zpos;
        int ret;
 
        ret = mixer_initialize(ctx, drm_dev);
        if (ret)
                return ret;
 
-       ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
-                                    EXYNOS_DISPLAY_TYPE_HDMI,
-                                    &mixer_crtc_ops, ctx);
+       for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
+               type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
+                                               DRM_PLANE_TYPE_OVERLAY;
+               ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
+                                       1 << ctx->pipe, type, zpos);
+               if (ret)
+                       return ret;
+       }
+
+       exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
+       ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
+                                          ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
+                                          &mixer_crtc_ops, ctx);
        if (IS_ERR(ctx->crtc)) {
                mixer_ctx_remove(ctx);
                ret = PTR_ERR(ctx->crtc);
index 5f32e1a..ac60260 100644 (file)
 #define MXR_CFG_GRP0_ENABLE            (1 << 4)
 #define MXR_CFG_VP_ENABLE              (1 << 3)
 #define MXR_CFG_SCAN_INTERLACE         (0 << 2)
-#define MXR_CFG_SCAN_PROGRASSIVE       (1 << 2)
+#define MXR_CFG_SCAN_PROGRESSIVE       (1 << 2)
 #define MXR_CFG_SCAN_NTSC              (0 << 1)
 #define MXR_CFG_SCAN_PAL               (1 << 1)
 #define MXR_CFG_SCAN_SD                        (0 << 0)
index d3ebaf2..a69002e 100644 (file)
@@ -28,6 +28,7 @@ i915-y += i915_cmd_parser.o \
          i915_gem_execbuffer.o \
          i915_gem_gtt.o \
          i915_gem.o \
+         i915_gem_shrinker.o \
          i915_gem_stolen.o \
          i915_gem_tiling.o \
          i915_gem_userptr.o \
index 1a52d6a..007c7d7 100644 (file)
@@ -1200,6 +1200,9 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
 
                seq_printf(m, "Max overclocked frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
+
+               seq_printf(m, "Idle freq: %d MHz\n",
+                          intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq));
        } else if (IS_VALLEYVIEW(dev)) {
                u32 freq_sts;
 
@@ -1214,6 +1217,9 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                seq_printf(m, "min GPU freq: %d MHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.min_freq));
 
+               seq_printf(m, "idle GPU freq: %d MHz\n",
+                          intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq));
+
                seq_printf(m,
                           "efficient (RPe) frequency: %d MHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
@@ -2308,7 +2314,7 @@ static int i915_sink_crc(struct seq_file *m, void *data)
        u8 crc[6];
 
        drm_modeset_lock_all(dev);
-       for_each_intel_encoder(dev, connector) {
+       for_each_intel_connector(dev, connector) {
 
                if (connector->base.dpms != DRM_MODE_DPMS_ON)
                        continue;
index d49ed68..68e0c85 100644 (file)
@@ -1199,7 +1199,7 @@ const struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, intel_sprite_get_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
        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),
index 8ba7e1b..e326ac9 100644 (file)
@@ -56,7 +56,7 @@
 
 #define DRIVER_NAME            "i915"
 #define DRIVER_DESC            "Intel Graphics"
-#define DRIVER_DATE            "20150313"
+#define DRIVER_DATE            "20150327"
 
 #undef WARN_ON
 /* Many gcc seem to no see through this and fall over :( */
@@ -427,6 +427,8 @@ struct drm_i915_error_state {
        u32 forcewake;
        u32 error; /* gen6+ */
        u32 err_int; /* gen7 */
+       u32 fault_data0; /* gen8, gen9 */
+       u32 fault_data1; /* gen8, gen9 */
        u32 done_reg;
        u32 gac_eco;
        u32 gam_ecochk;
@@ -544,7 +546,7 @@ struct drm_i915_display_funcs {
         * Returns true on success, false on failure.
         */
        bool (*find_dpll)(const struct intel_limit *limit,
-                         struct intel_crtc *crtc,
+                         struct intel_crtc_state *crtc_state,
                          int target, int refclk,
                          struct dpll *match_clock,
                          struct dpll *best_clock);
@@ -553,7 +555,7 @@ struct drm_i915_display_funcs {
                                 struct drm_crtc *crtc,
                                 uint32_t sprite_width, uint32_t sprite_height,
                                 int pixel_size, bool enable, bool scaled);
-       void (*modeset_global_resources)(struct drm_device *dev);
+       void (*modeset_global_resources)(struct drm_atomic_state *state);
        /* Returns the active state of the crtc, and if the crtc is active,
         * fills out the pipe-config with the hw state. */
        bool (*get_pipe_config)(struct intel_crtc *,
@@ -1025,13 +1027,12 @@ struct intel_gen6_power_mgmt {
        u8 max_freq_softlimit;  /* Max frequency permitted by the driver */
        u8 max_freq;            /* Maximum frequency, RP0 if not overclocking */
        u8 min_freq;            /* AKA RPn. Minimum frequency */
+       u8 idle_freq;           /* Frequency to request when we are idle */
        u8 efficient_freq;      /* AKA RPe. Pre-determined balanced frequency */
        u8 rp1_freq;            /* "less than" RP0 power/freqency */
        u8 rp0_freq;            /* Non-overclocked max frequency. */
        u32 cz_freq;
 
-       u32 ei_interrupt_count;
-
        int last_adj;
        enum { LOW_POWER, BETWEEN, HIGH_POWER } power;
 
@@ -2442,7 +2443,6 @@ extern int i915_resume_legacy(struct drm_device *dev);
 struct i915_params {
        int modeset;
        int panel_ignore_lid;
-       unsigned int powersave;
        int semaphores;
        unsigned int lvds_downclock;
        int lvds_channel_mode;
@@ -2462,6 +2462,7 @@ struct i915_params {
        bool enable_hangcheck;
        bool fastboot;
        bool prefault_disable;
+       bool load_detect_test;
        bool reset;
        bool disable_display;
        bool disable_vtd_wa;
@@ -2601,12 +2602,6 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 void i915_gem_load(struct drm_device *dev);
-unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
-                             long target,
-                             unsigned flags);
-#define I915_SHRINK_PURGEABLE 0x1
-#define I915_SHRINK_UNBOUND 0x2
-#define I915_SHRINK_BOUND 0x4
 void *i915_gem_object_alloc(struct drm_device *dev);
 void i915_gem_object_free(struct drm_i915_gem_object *obj);
 void i915_gem_object_init(struct drm_i915_gem_object *obj,
@@ -2623,20 +2618,16 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
 #define PIN_GLOBAL 0x4
 #define PIN_OFFSET_BIAS 0x8
 #define PIN_OFFSET_MASK (~4095)
-int __must_check i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
-                                         struct i915_address_space *vm,
-                                         uint32_t alignment,
-                                         uint64_t flags,
-                                         const struct i915_ggtt_view *view);
-static inline
-int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
-                                    struct i915_address_space *vm,
-                                    uint32_t alignment,
-                                    uint64_t flags)
-{
-       return i915_gem_object_pin_view(obj, vm, alignment, flags,
-                                               &i915_ggtt_view_normal);
-}
+int __must_check
+i915_gem_object_pin(struct drm_i915_gem_object *obj,
+                   struct i915_address_space *vm,
+                   uint32_t alignment,
+                   uint64_t flags);
+int __must_check
+i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
+                        const struct i915_ggtt_view *view,
+                        uint32_t alignment,
+                        uint64_t flags);
 
 int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
                  u32 flags);
@@ -2776,8 +2767,10 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write);
 int __must_check
 i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                     u32 alignment,
-                                    struct intel_engine_cs *pipelined);
-void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj);
+                                    struct intel_engine_cs *pipelined,
+                                    const struct i915_ggtt_view *view);
+void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
+                                             const struct i915_ggtt_view *view);
 int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj,
                                int align);
 int i915_gem_open(struct drm_device *dev, struct drm_file *file);
@@ -2800,60 +2793,46 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
 
 void i915_gem_restore_fences(struct drm_device *dev);
 
-unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
-                                      struct i915_address_space *vm,
-                                      enum i915_ggtt_view_type view);
-static inline
-unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
-                                 struct i915_address_space *vm)
+unsigned long
+i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
+                             const struct i915_ggtt_view *view);
+unsigned long
+i915_gem_obj_offset(struct drm_i915_gem_object *o,
+                   struct i915_address_space *vm);
+static inline unsigned long
+i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *o)
 {
-       return i915_gem_obj_offset_view(o, vm, I915_GGTT_VIEW_NORMAL);
+       return i915_gem_obj_ggtt_offset_view(o, &i915_ggtt_view_normal);
 }
+
 bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o);
-bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
-                            struct i915_address_space *vm,
-                            enum i915_ggtt_view_type view);
-static inline
+bool i915_gem_obj_ggtt_bound_view(struct drm_i915_gem_object *o,
+                                 const struct i915_ggtt_view *view);
 bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
-                       struct i915_address_space *vm)
-{
-       return i915_gem_obj_bound_view(o, vm, I915_GGTT_VIEW_NORMAL);
-}
+                       struct i915_address_space *vm);
 
 unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
                                struct i915_address_space *vm);
-struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
-                                         struct i915_address_space *vm,
-                                         const struct i915_ggtt_view *view);
-static inline
-struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
-                                    struct i915_address_space *vm)
-{
-       return i915_gem_obj_to_vma_view(obj, vm, &i915_ggtt_view_normal);
-}
-
 struct i915_vma *
-i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
-                                      struct i915_address_space *vm,
-                                      const struct i915_ggtt_view *view);
+i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
+                   struct i915_address_space *vm);
+struct i915_vma *
+i915_gem_obj_to_ggtt_view(struct drm_i915_gem_object *obj,
+                         const struct i915_ggtt_view *view);
 
-static inline
 struct i915_vma *
 i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
-                                 struct i915_address_space *vm)
-{
-       return i915_gem_obj_lookup_or_create_vma_view(obj, vm,
-                                               &i915_ggtt_view_normal);
-}
+                                 struct i915_address_space *vm);
+struct i915_vma *
+i915_gem_obj_lookup_or_create_ggtt_vma(struct drm_i915_gem_object *obj,
+                                      const struct i915_ggtt_view *view);
 
-struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj);
-static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
-       struct i915_vma *vma;
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (vma->pin_count > 0)
-                       return true;
-       return false;
+static inline struct i915_vma *
+i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
+{
+       return i915_gem_obj_to_ggtt_view(obj, &i915_ggtt_view_normal);
 }
+bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj);
 
 /* Some GGTT VM helpers */
 #define i915_obj_to_ggtt(obj) \
@@ -2876,13 +2855,7 @@ i915_vm_to_ppgtt(struct i915_address_space *vm)
 
 static inline bool i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *obj)
 {
-       return i915_gem_obj_bound(obj, i915_obj_to_ggtt(obj));
-}
-
-static inline unsigned long
-i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *obj)
-{
-       return i915_gem_obj_offset(obj, i915_obj_to_ggtt(obj));
+       return i915_gem_obj_ggtt_bound_view(obj, &i915_ggtt_view_normal);
 }
 
 static inline unsigned long
@@ -2906,7 +2879,13 @@ i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj)
        return i915_vma_unbind(i915_gem_obj_to_ggtt(obj));
 }
 
-void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj);
+void i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj,
+                                    const struct i915_ggtt_view *view);
+static inline void
+i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj)
+{
+       i915_gem_object_ggtt_unpin_view(obj, &i915_ggtt_view_normal);
+}
 
 /* i915_gem_context.c */
 int __must_check i915_gem_context_init(struct drm_device *dev);
@@ -2978,6 +2957,17 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
                                               u32 gtt_offset,
                                               u32 size);
 
+/* i915_gem_shrinker.c */
+unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
+                             long target,
+                             unsigned flags);
+#define I915_SHRINK_PURGEABLE 0x1
+#define I915_SHRINK_UNBOUND 0x2
+#define I915_SHRINK_BOUND 0x4
+unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
+void i915_gem_shrinker_init(struct drm_i915_private *dev_priv);
+
+
 /* i915_gem_tiling.c */
 static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj)
 {
index 0fe313d..d07c0b1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright Â© 2008 Intel Corporation
+ * Copyright Â© 2008-2015 Intel Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -32,7 +32,6 @@
 #include "i915_vgpu.h"
 #include "i915_trace.h"
 #include "intel_drv.h"
-#include <linux/oom.h>
 #include <linux/shmem_fs.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
@@ -53,15 +52,6 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
                                         struct drm_i915_fence_reg *fence,
                                         bool enable);
 
-static unsigned long i915_gem_shrinker_count(struct shrinker *shrinker,
-                                            struct shrink_control *sc);
-static unsigned long i915_gem_shrinker_scan(struct shrinker *shrinker,
-                                           struct shrink_control *sc);
-static int i915_gem_shrinker_oom(struct notifier_block *nb,
-                                unsigned long event,
-                                void *ptr);
-static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
-
 static bool cpu_cache_is_coherent(struct drm_device *dev,
                                  enum i915_cache_level level)
 {
@@ -1936,12 +1926,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
        return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
 }
 
-static inline int
-i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
-{
-       return obj->madv == I915_MADV_DONTNEED;
-}
-
 /* Immediately discard the backing storage */
 static void
 i915_gem_object_truncate(struct drm_i915_gem_object *obj)
@@ -2047,85 +2031,6 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
        return 0;
 }
 
-unsigned long
-i915_gem_shrink(struct drm_i915_private *dev_priv,
-               long target, unsigned flags)
-{
-       const struct {
-               struct list_head *list;
-               unsigned int bit;
-       } phases[] = {
-               { &dev_priv->mm.unbound_list, I915_SHRINK_UNBOUND },
-               { &dev_priv->mm.bound_list, I915_SHRINK_BOUND },
-               { NULL, 0 },
-       }, *phase;
-       unsigned long count = 0;
-
-       /*
-        * As we may completely rewrite the (un)bound list whilst unbinding
-        * (due to retiring requests) we have to strictly process only
-        * one element of the list at the time, and recheck the list
-        * on every iteration.
-        *
-        * In particular, we must hold a reference whilst removing the
-        * object as we may end up waiting for and/or retiring the objects.
-        * This might release the final reference (held by the active list)
-        * and result in the object being freed from under us. This is
-        * similar to the precautions the eviction code must take whilst
-        * removing objects.
-        *
-        * Also note that although these lists do not hold a reference to
-        * the object we can safely grab one here: The final object
-        * unreferencing and the bound_list are both protected by the
-        * dev->struct_mutex and so we won't ever be able to observe an
-        * object on the bound_list with a reference count equals 0.
-        */
-       for (phase = phases; phase->list; phase++) {
-               struct list_head still_in_list;
-
-               if ((flags & phase->bit) == 0)
-                       continue;
-
-               INIT_LIST_HEAD(&still_in_list);
-               while (count < target && !list_empty(phase->list)) {
-                       struct drm_i915_gem_object *obj;
-                       struct i915_vma *vma, *v;
-
-                       obj = list_first_entry(phase->list,
-                                              typeof(*obj), global_list);
-                       list_move_tail(&obj->global_list, &still_in_list);
-
-                       if (flags & I915_SHRINK_PURGEABLE &&
-                           !i915_gem_object_is_purgeable(obj))
-                               continue;
-
-                       drm_gem_object_reference(&obj->base);
-
-                       /* For the unbound phase, this should be a no-op! */
-                       list_for_each_entry_safe(vma, v,
-                                                &obj->vma_list, vma_link)
-                               if (i915_vma_unbind(vma))
-                                       break;
-
-                       if (i915_gem_object_put_pages(obj) == 0)
-                               count += obj->base.size >> PAGE_SHIFT;
-
-                       drm_gem_object_unreference(&obj->base);
-               }
-               list_splice(&still_in_list, phase->list);
-       }
-
-       return count;
-}
-
-static unsigned long
-i915_gem_shrink_all(struct drm_i915_private *dev_priv)
-{
-       i915_gem_evict_everything(dev_priv->dev);
-       return i915_gem_shrink(dev_priv, LONG_MAX,
-                              I915_SHRINK_BOUND | I915_SHRINK_UNBOUND);
-}
-
 static int
 i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
 {
@@ -2755,24 +2660,11 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
        WARN_ON(i915_verify_lists(ring->dev));
 
-       /* Move any buffers on the active list that are no longer referenced
-        * by the ringbuffer to the flushing/inactive lists as appropriate,
-        * before we free the context associated with the requests.
+       /* Retire requests first as we use it above for the early return.
+        * If we retire requests last, we may use a later seqno and so clear
+        * the requests lists without clearing the active list, leading to
+        * confusion.
         */
-       while (!list_empty(&ring->active_list)) {
-               struct drm_i915_gem_object *obj;
-
-               obj = list_first_entry(&ring->active_list,
-                                     struct drm_i915_gem_object,
-                                     ring_list);
-
-               if (!i915_gem_request_completed(obj->last_read_req, true))
-                       break;
-
-               i915_gem_object_move_to_inactive(obj);
-       }
-
-
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
 
@@ -2795,6 +2687,23 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
                i915_gem_free_request(request);
        }
 
+       /* Move any buffers on the active list that are no longer referenced
+        * by the ringbuffer to the flushing/inactive lists as appropriate,
+        * before we free the context associated with the requests.
+        */
+       while (!list_empty(&ring->active_list)) {
+               struct drm_i915_gem_object *obj;
+
+               obj = list_first_entry(&ring->active_list,
+                                     struct drm_i915_gem_object,
+                                     ring_list);
+
+               if (!i915_gem_request_completed(obj->last_read_req, true))
+                       break;
+
+               i915_gem_object_move_to_inactive(obj);
+       }
+
        if (unlikely(ring->trace_irq_req &&
                     i915_gem_request_completed(ring->trace_irq_req, true))) {
                ring->irq_put(ring);
@@ -3518,9 +3427,9 @@ static bool i915_gem_valid_gtt_space(struct i915_vma *vma,
 static struct i915_vma *
 i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
                           struct i915_address_space *vm,
+                          const struct i915_ggtt_view *ggtt_view,
                           unsigned alignment,
-                          uint64_t flags,
-                          const struct i915_ggtt_view *view)
+                          uint64_t flags)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3532,6 +3441,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
        struct i915_vma *vma;
        int ret;
 
+       if(WARN_ON(i915_is_ggtt(vm) != !!ggtt_view))
+               return ERR_PTR(-EINVAL);
+
        fence_size = i915_gem_get_gtt_size(dev,
                                           obj->base.size,
                                           obj->tiling_mode);
@@ -3570,7 +3482,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
 
        i915_gem_object_pin_pages(obj);
 
-       vma = i915_gem_obj_lookup_or_create_vma_view(obj, vm, view);
+       vma = ggtt_view ? i915_gem_obj_lookup_or_create_ggtt_vma(obj, ggtt_view) :
+                         i915_gem_obj_lookup_or_create_vma(obj, vm);
+
        if (IS_ERR(vma))
                goto err_unpin;
 
@@ -3600,6 +3514,17 @@ search_free:
        if (ret)
                goto err_remove_node;
 
+       /*  allocate before insert / bind */
+       if (vma->vm->allocate_va_range) {
+               trace_i915_va_alloc(vma->vm, vma->node.start, vma->node.size,
+                               VM_TO_TRACE_NAME(vma->vm));
+               ret = vma->vm->allocate_va_range(vma->vm,
+                                               vma->node.start,
+                                               vma->node.size);
+               if (ret)
+                       goto err_remove_node;
+       }
+
        trace_i915_vma_bind(vma, flags);
        ret = i915_vma_bind(vma, obj->cache_level,
                            flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
@@ -3952,7 +3877,8 @@ static bool is_pin_display(struct drm_i915_gem_object *obj)
 int
 i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                     u32 alignment,
-                                    struct intel_engine_cs *pipelined)
+                                    struct intel_engine_cs *pipelined,
+                                    const struct i915_ggtt_view *view)
 {
        u32 old_read_domains, old_write_domain;
        bool was_pin_display;
@@ -3988,7 +3914,9 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
         * (e.g. libkms for the bootup splash), we have to ensure that we
         * always use map_and_fenceable for all scanout buffers.
         */
-       ret = i915_gem_obj_ggtt_pin(obj, alignment, PIN_MAPPABLE);
+       ret = i915_gem_object_ggtt_pin(obj, view, alignment,
+                                      view->type == I915_GGTT_VIEW_NORMAL ?
+                                      PIN_MAPPABLE : 0);
        if (ret)
                goto err_unpin_display;
 
@@ -4016,9 +3944,11 @@ err_unpin_display:
 }
 
 void
-i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj)
+i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
+                                        const struct i915_ggtt_view *view)
 {
-       i915_gem_object_ggtt_unpin(obj);
+       i915_gem_object_ggtt_unpin_view(obj, view);
+
        obj->pin_display = is_pin_display(obj);
 }
 
@@ -4167,12 +4097,12 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
        return false;
 }
 
-int
-i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
-                        struct i915_address_space *vm,
-                        uint32_t alignment,
-                        uint64_t flags,
-                        const struct i915_ggtt_view *view)
+static int
+i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
+                      struct i915_address_space *vm,
+                      const struct i915_ggtt_view *ggtt_view,
+                      uint32_t alignment,
+                      uint64_t flags)
 {
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
        struct i915_vma *vma;
@@ -4188,17 +4118,29 @@ i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
        if (WARN_ON((flags & (PIN_MAPPABLE | PIN_GLOBAL)) == PIN_MAPPABLE))
                return -EINVAL;
 
-       vma = i915_gem_obj_to_vma_view(obj, vm, view);
+       if (WARN_ON(i915_is_ggtt(vm) != !!ggtt_view))
+               return -EINVAL;
+
+       vma = ggtt_view ? i915_gem_obj_to_ggtt_view(obj, ggtt_view) :
+                         i915_gem_obj_to_vma(obj, vm);
+
+       if (IS_ERR(vma))
+               return PTR_ERR(vma);
+
        if (vma) {
                if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
                        return -EBUSY;
 
                if (i915_vma_misplaced(vma, alignment, flags)) {
+                       unsigned long offset;
+                       offset = ggtt_view ? i915_gem_obj_ggtt_offset_view(obj, ggtt_view) :
+                                            i915_gem_obj_offset(obj, vm);
                        WARN(vma->pin_count,
-                            "bo is already pinned with incorrect alignment:"
+                            "bo is already pinned in %s with incorrect alignment:"
                             " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
                             " obj->map_and_fenceable=%d\n",
-                            i915_gem_obj_offset_view(obj, vm, view->type),
+                            ggtt_view ? "ggtt" : "ppgtt",
+                            offset,
                             alignment,
                             !!(flags & PIN_MAPPABLE),
                             obj->map_and_fenceable);
@@ -4212,8 +4154,12 @@ i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
 
        bound = vma ? vma->bound : 0;
        if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
-               vma = i915_gem_object_bind_to_vm(obj, vm, alignment,
-                                                flags, view);
+               /* In true PPGTT, bind has possibly changed PDEs, which
+                * means we must do a context switch before the GPU can
+                * accurately read some of the VMAs.
+                */
+               vma = i915_gem_object_bind_to_vm(obj, vm, ggtt_view, alignment,
+                                                flags);
                if (IS_ERR(vma))
                        return PTR_ERR(vma);
        }
@@ -4254,16 +4200,41 @@ i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
        return 0;
 }
 
+int
+i915_gem_object_pin(struct drm_i915_gem_object *obj,
+                   struct i915_address_space *vm,
+                   uint32_t alignment,
+                   uint64_t flags)
+{
+       return i915_gem_object_do_pin(obj, vm,
+                                     i915_is_ggtt(vm) ? &i915_ggtt_view_normal : NULL,
+                                     alignment, flags);
+}
+
+int
+i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
+                        const struct i915_ggtt_view *view,
+                        uint32_t alignment,
+                        uint64_t flags)
+{
+       if (WARN_ONCE(!view, "no view specified"))
+               return -EINVAL;
+
+       return i915_gem_object_do_pin(obj, i915_obj_to_ggtt(obj), view,
+                                     alignment, flags | PIN_GLOBAL);
+}
+
 void
-i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj)
+i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj,
+                               const struct i915_ggtt_view *view)
 {
-       struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
+       struct i915_vma *vma = i915_gem_obj_to_ggtt_view(obj, view);
 
        BUG_ON(!vma);
-       BUG_ON(vma->pin_count == 0);
-       BUG_ON(!i915_gem_obj_ggtt_bound(obj));
+       WARN_ON(vma->pin_count == 0);
+       WARN_ON(!i915_gem_obj_ggtt_bound_view(obj, view));
 
-       if (--vma->pin_count == 0)
+       if (--vma->pin_count == 0 && view->type == I915_GGTT_VIEW_NORMAL)
                obj->pin_mappable = false;
 }
 
@@ -4384,7 +4355,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
                obj->madv = args->madv;
 
        /* if the object is no longer attached, discard its backing storage */
-       if (i915_gem_object_is_purgeable(obj) && obj->pages == NULL)
+       if (obj->madv == I915_MADV_DONTNEED && obj->pages == NULL)
                i915_gem_object_truncate(obj);
 
        args->retained = obj->madv != __I915_MADV_PURGED;
@@ -4559,15 +4530,33 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
        intel_runtime_pm_put(dev_priv);
 }
 
-struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
-                                         struct i915_address_space *vm,
-                                         const struct i915_ggtt_view *view)
+struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
+                                    struct i915_address_space *vm)
 {
        struct i915_vma *vma;
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (vma->vm == vm && vma->ggtt_view.type == view->type)
+       list_for_each_entry(vma, &obj->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
+               if (vma->vm == vm)
                        return vma;
+       }
+       return NULL;
+}
 
+struct i915_vma *i915_gem_obj_to_ggtt_view(struct drm_i915_gem_object *obj,
+                                          const struct i915_ggtt_view *view)
+{
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
+       struct i915_vma *vma;
+
+       if (WARN_ONCE(!view, "no view specified"))
+               return ERR_PTR(-EINVAL);
+
+       list_for_each_entry(vma, &obj->vma_list, vma_link)
+               if (vma->vm == ggtt &&
+                   i915_ggtt_view_equal(&vma->ggtt_view, view))
+                       return vma;
        return NULL;
 }
 
@@ -5006,13 +4995,7 @@ i915_gem_load(struct drm_device *dev)
 
        dev_priv->mm.interruptible = true;
 
-       dev_priv->mm.shrinker.scan_objects = i915_gem_shrinker_scan;
-       dev_priv->mm.shrinker.count_objects = i915_gem_shrinker_count;
-       dev_priv->mm.shrinker.seeks = DEFAULT_SEEKS;
-       register_shrinker(&dev_priv->mm.shrinker);
-
-       dev_priv->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom;
-       register_oom_notifier(&dev_priv->mm.oom_notifier);
+       i915_gem_shrinker_init(dev_priv);
 
        i915_gem_batch_pool_init(dev, &dev_priv->mm.batch_pool);
 
@@ -5104,106 +5087,70 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
        }
 }
 
-static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
-{
-       if (!mutex_is_locked(mutex))
-               return false;
-
-#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
-       return mutex->owner == task;
-#else
-       /* Since UP may be pre-empted, we cannot assume that we own the lock */
-       return false;
-#endif
-}
-
-static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock)
+/* All the new VM stuff */
+unsigned long
+i915_gem_obj_offset(struct drm_i915_gem_object *o,
+                   struct i915_address_space *vm)
 {
-       if (!mutex_trylock(&dev->struct_mutex)) {
-               if (!mutex_is_locked_by(&dev->struct_mutex, current))
-                       return false;
+       struct drm_i915_private *dev_priv = o->base.dev->dev_private;
+       struct i915_vma *vma;
 
-               if (to_i915(dev)->mm.shrinker_no_lock_stealing)
-                       return false;
+       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
 
-               *unlock = false;
-       } else
-               *unlock = true;
+       list_for_each_entry(vma, &o->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
+               if (vma->vm == vm)
+                       return vma->node.start;
+       }
 
-       return true;
+       WARN(1, "%s vma for this object not found.\n",
+            i915_is_ggtt(vm) ? "global" : "ppgtt");
+       return -1;
 }
 
-static int num_vma_bound(struct drm_i915_gem_object *obj)
+unsigned long
+i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
+                             const struct i915_ggtt_view *view)
 {
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(o);
        struct i915_vma *vma;
-       int count = 0;
-
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (drm_mm_node_allocated(&vma->node))
-                       count++;
 
-       return count;
-}
-
-static unsigned long
-i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(shrinker, struct drm_i915_private, mm.shrinker);
-       struct drm_device *dev = dev_priv->dev;
-       struct drm_i915_gem_object *obj;
-       unsigned long count;
-       bool unlock;
-
-       if (!i915_gem_shrinker_lock(dev, &unlock))
-               return 0;
-
-       count = 0;
-       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
-               if (obj->pages_pin_count == 0)
-                       count += obj->base.size >> PAGE_SHIFT;
-
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (!i915_gem_obj_is_pinned(obj) &&
-                   obj->pages_pin_count == num_vma_bound(obj))
-                       count += obj->base.size >> PAGE_SHIFT;
-       }
-
-       if (unlock)
-               mutex_unlock(&dev->struct_mutex);
+       list_for_each_entry(vma, &o->vma_list, vma_link)
+               if (vma->vm == ggtt &&
+                   i915_ggtt_view_equal(&vma->ggtt_view, view))
+                       return vma->node.start;
 
-       return count;
+       WARN(1, "global vma for this object not found.\n");
+       return -1;
 }
 
-/* All the new VM stuff */
-unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
-                                      struct i915_address_space *vm,
-                                      enum i915_ggtt_view_type view)
+bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
+                       struct i915_address_space *vm)
 {
-       struct drm_i915_private *dev_priv = o->base.dev->dev_private;
        struct i915_vma *vma;
 
-       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
-
        list_for_each_entry(vma, &o->vma_list, vma_link) {
-               if (vma->vm == vm && vma->ggtt_view.type == view)
-                       return vma->node.start;
-
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
+               if (vma->vm == vm && drm_mm_node_allocated(&vma->node))
+                       return true;
        }
-       WARN(1, "%s vma for this object not found.\n",
-            i915_is_ggtt(vm) ? "global" : "ppgtt");
-       return -1;
+
+       return false;
 }
 
-bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
-                            struct i915_address_space *vm,
-                            enum i915_ggtt_view_type view)
+bool i915_gem_obj_ggtt_bound_view(struct drm_i915_gem_object *o,
+                                 const struct i915_ggtt_view *view)
 {
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(o);
        struct i915_vma *vma;
 
        list_for_each_entry(vma, &o->vma_list, vma_link)
-               if (vma->vm == vm &&
-                   vma->ggtt_view.type == view &&
+               if (vma->vm == ggtt &&
+                   i915_ggtt_view_equal(&vma->ggtt_view, view) &&
                    drm_mm_node_allocated(&vma->node))
                        return true;
 
@@ -5231,118 +5178,26 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
 
        BUG_ON(list_empty(&o->vma_list));
 
-       list_for_each_entry(vma, &o->vma_list, vma_link)
+       list_for_each_entry(vma, &o->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
                if (vma->vm == vm)
                        return vma->node.size;
-
+       }
        return 0;
 }
 
-static unsigned long
-i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
+bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj)
 {
-       struct drm_i915_private *dev_priv =
-               container_of(shrinker, struct drm_i915_private, mm.shrinker);
-       struct drm_device *dev = dev_priv->dev;
-       unsigned long freed;
-       bool unlock;
-
-       if (!i915_gem_shrinker_lock(dev, &unlock))
-               return SHRINK_STOP;
-
-       freed = i915_gem_shrink(dev_priv,
-                               sc->nr_to_scan,
-                               I915_SHRINK_BOUND |
-                               I915_SHRINK_UNBOUND |
-                               I915_SHRINK_PURGEABLE);
-       if (freed < sc->nr_to_scan)
-               freed += i915_gem_shrink(dev_priv,
-                                        sc->nr_to_scan - freed,
-                                        I915_SHRINK_BOUND |
-                                        I915_SHRINK_UNBOUND);
-       if (unlock)
-               mutex_unlock(&dev->struct_mutex);
-
-       return freed;
-}
-
-static int
-i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(nb, struct drm_i915_private, mm.oom_notifier);
-       struct drm_device *dev = dev_priv->dev;
-       struct drm_i915_gem_object *obj;
-       unsigned long timeout = msecs_to_jiffies(5000) + 1;
-       unsigned long pinned, bound, unbound, freed_pages;
-       bool was_interruptible;
-       bool unlock;
-
-       while (!i915_gem_shrinker_lock(dev, &unlock) && --timeout) {
-               schedule_timeout_killable(1);
-               if (fatal_signal_pending(current))
-                       return NOTIFY_DONE;
-       }
-       if (timeout == 0) {
-               pr_err("Unable to purge GPU memory due lock contention.\n");
-               return NOTIFY_DONE;
-       }
-
-       was_interruptible = dev_priv->mm.interruptible;
-       dev_priv->mm.interruptible = false;
-
-       freed_pages = i915_gem_shrink_all(dev_priv);
-
-       dev_priv->mm.interruptible = was_interruptible;
-
-       /* Because we may be allocating inside our own driver, we cannot
-        * assert that there are no objects with pinned pages that are not
-        * being pointed to by hardware.
-        */
-       unbound = bound = pinned = 0;
-       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
-               if (!obj->base.filp) /* not backed by a freeable object */
-                       continue;
-
-               if (obj->pages_pin_count)
-                       pinned += obj->base.size;
-               else
-                       unbound += obj->base.size;
-       }
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (!obj->base.filp)
+       struct i915_vma *vma;
+       list_for_each_entry(vma, &obj->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
                        continue;
-
-               if (obj->pages_pin_count)
-                       pinned += obj->base.size;
-               else
-                       bound += obj->base.size;
+               if (vma->pin_count > 0)
+                       return true;
        }
-
-       if (unlock)
-               mutex_unlock(&dev->struct_mutex);
-
-       if (freed_pages || unbound || bound)
-               pr_info("Purging GPU memory, %lu bytes freed, %lu bytes still pinned.\n",
-                       freed_pages << PAGE_SHIFT, pinned);
-       if (unbound || bound)
-               pr_err("%lu and %lu bytes still available in the "
-                      "bound and unbound GPU page lists.\n",
-                      bound, unbound);
-
-       *(unsigned long *)ptr += freed_pages;
-       return NOTIFY_DONE;
+       return false;
 }
 
-struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
-{
-       struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
-       struct i915_vma *vma;
-
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (vma->vm == ggtt &&
-                   vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
-                       return vma;
-
-       return NULL;
-}
index 70346b0..f3e84c4 100644 (file)
@@ -569,6 +569,66 @@ mi_set_context(struct intel_engine_cs *ring,
        return ret;
 }
 
+static inline bool should_skip_switch(struct intel_engine_cs *ring,
+                                     struct intel_context *from,
+                                     struct intel_context *to)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+       if (to->remap_slice)
+               return false;
+
+       if (to->ppgtt) {
+               if (from == to && !test_bit(ring->id,
+                               &to->ppgtt->pd_dirty_rings))
+                       return true;
+       } else if (dev_priv->mm.aliasing_ppgtt) {
+               if (from == to && !test_bit(ring->id,
+                               &dev_priv->mm.aliasing_ppgtt->pd_dirty_rings))
+                       return true;
+       }
+
+       return false;
+}
+
+static bool
+needs_pd_load_pre(struct intel_engine_cs *ring, struct intel_context *to)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+       if (!to->ppgtt)
+               return false;
+
+       if (INTEL_INFO(ring->dev)->gen < 8)
+               return true;
+
+       if (ring != &dev_priv->ring[RCS])
+               return true;
+
+       return false;
+}
+
+static bool
+needs_pd_load_post(struct intel_engine_cs *ring, struct intel_context *to,
+               u32 hw_flags)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+       if (!to->ppgtt)
+               return false;
+
+       if (!IS_GEN8(ring->dev))
+               return false;
+
+       if (ring != &dev_priv->ring[RCS])
+               return false;
+
+       if (hw_flags & MI_RESTORE_INHIBIT)
+               return true;
+
+       return false;
+}
+
 static int do_switch(struct intel_engine_cs *ring,
                     struct intel_context *to)
 {
@@ -584,7 +644,7 @@ static int do_switch(struct intel_engine_cs *ring,
                BUG_ON(!i915_gem_obj_is_pinned(from->legacy_hw_ctx.rcs_state));
        }
 
-       if (from == to && !to->remap_slice)
+       if (should_skip_switch(ring, from, to))
                return 0;
 
        /* Trying to pin first makes error handling easier. */
@@ -602,11 +662,18 @@ static int do_switch(struct intel_engine_cs *ring,
         */
        from = ring->last_context;
 
-       if (to->ppgtt) {
+       if (needs_pd_load_pre(ring, to)) {
+               /* Older GENs and non render rings still want the load first,
+                * "PP_DCLV followed by PP_DIR_BASE register through Load
+                * Register Immediate commands in Ring Buffer before submitting
+                * a context."*/
                trace_switch_mm(ring, to);
                ret = to->ppgtt->switch_mm(to->ppgtt, ring);
                if (ret)
                        goto unpin_out;
+
+               /* Doing a PD load always reloads the page dirs */
+               clear_bit(ring->id, &to->ppgtt->pd_dirty_rings);
        }
 
        if (ring != &dev_priv->ring[RCS]) {
@@ -637,13 +704,41 @@ static int do_switch(struct intel_engine_cs *ring,
                        goto unpin_out;
        }
 
-       if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to))
+       if (!to->legacy_hw_ctx.initialized) {
                hw_flags |= MI_RESTORE_INHIBIT;
+               /* NB: If we inhibit the restore, the context is not allowed to
+                * die because future work may end up depending on valid address
+                * space. This means we must enforce that a page table load
+                * occur when this occurs. */
+       } else if (to->ppgtt &&
+                       test_and_clear_bit(ring->id, &to->ppgtt->pd_dirty_rings))
+               hw_flags |= MI_FORCE_RESTORE;
+
+       /* We should never emit switch_mm more than once */
+       WARN_ON(needs_pd_load_pre(ring, to) &&
+                       needs_pd_load_post(ring, to, hw_flags));
 
        ret = mi_set_context(ring, to, hw_flags);
        if (ret)
                goto unpin_out;
 
+       /* GEN8 does *not* require an explicit reload if the PDPs have been
+        * setup, and we do not wish to move them.
+        */
+       if (needs_pd_load_post(ring, to, hw_flags)) {
+               trace_switch_mm(ring, to);
+               ret = to->ppgtt->switch_mm(to->ppgtt, ring);
+               /* The hardware context switch is emitted, but we haven't
+                * actually changed the state - so it's probably safe to bail
+                * here. Still, let the user know something dangerous has
+                * happened.
+                */
+               if (ret) {
+                       DRM_ERROR("Failed to change address space on context switch\n");
+                       goto unpin_out;
+               }
+       }
+
        for (i = 0; i < MAX_L3_SLICES; i++) {
                if (!(to->remap_slice & (1<<i)))
                        continue;
@@ -681,7 +776,7 @@ static int do_switch(struct intel_engine_cs *ring,
                i915_gem_context_unreference(from);
        }
 
-       uninitialized = !to->legacy_hw_ctx.initialized && from == NULL;
+       uninitialized = !to->legacy_hw_ctx.initialized;
        to->legacy_hw_ctx.initialized = true;
 
 done:
index e3a49d9..d09e35e 100644 (file)
@@ -63,6 +63,10 @@ mark_free(struct i915_vma *vma, struct list_head *unwind)
  *
  * This function is used by the object/vma binding code.
  *
+ * Since this function is only used to free up virtual address space it only
+ * ignores pinned vmas, and not object where the backing storage itself is
+ * pinned. Hence obj->pages_pin_count does not protect against eviction.
+ *
  * To clarify: This is for freeing up virtual address space, not for freeing
  * memory in e.g. the shrinker.
  */
index dc10bc4..a3190e7 100644 (file)
@@ -251,7 +251,6 @@ static inline int use_cpu_reloc(struct drm_i915_gem_object *obj)
 {
        return (HAS_LLC(obj->base.dev) ||
                obj->base.write_domain == I915_GEM_DOMAIN_CPU ||
-               !obj->map_and_fenceable ||
                obj->cache_level != I915_CACHE_NONE);
 }
 
@@ -337,6 +336,51 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
        return 0;
 }
 
+static void
+clflush_write32(void *addr, uint32_t value)
+{
+       /* This is not a fast path, so KISS. */
+       drm_clflush_virt_range(addr, sizeof(uint32_t));
+       *(uint32_t *)addr = value;
+       drm_clflush_virt_range(addr, sizeof(uint32_t));
+}
+
+static int
+relocate_entry_clflush(struct drm_i915_gem_object *obj,
+                      struct drm_i915_gem_relocation_entry *reloc,
+                      uint64_t target_offset)
+{
+       struct drm_device *dev = obj->base.dev;
+       uint32_t page_offset = offset_in_page(reloc->offset);
+       uint64_t delta = (int)reloc->delta + target_offset;
+       char *vaddr;
+       int ret;
+
+       ret = i915_gem_object_set_to_gtt_domain(obj, true);
+       if (ret)
+               return ret;
+
+       vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+                               reloc->offset >> PAGE_SHIFT));
+       clflush_write32(vaddr + page_offset, lower_32_bits(delta));
+
+       if (INTEL_INFO(dev)->gen >= 8) {
+               page_offset = offset_in_page(page_offset + sizeof(uint32_t));
+
+               if (page_offset == 0) {
+                       kunmap_atomic(vaddr);
+                       vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+                           (reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT));
+               }
+
+               clflush_write32(vaddr + page_offset, upper_32_bits(delta));
+       }
+
+       kunmap_atomic(vaddr);
+
+       return 0;
+}
+
 static int
 i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                                   struct eb_vmas *eb,
@@ -426,8 +470,14 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
 
        if (use_cpu_reloc(obj))
                ret = relocate_entry_cpu(obj, reloc, target_offset);
-       else
+       else if (obj->map_and_fenceable)
                ret = relocate_entry_gtt(obj, reloc, target_offset);
+       else if (cpu_has_clflush)
+               ret = relocate_entry_clflush(obj, reloc, target_offset);
+       else {
+               WARN_ONCE(1, "Impossible case in relocation handling\n");
+               ret = -ENODEV;
+       }
 
        if (ret)
                return ret;
@@ -525,6 +575,12 @@ i915_gem_execbuffer_relocate(struct eb_vmas *eb)
        return ret;
 }
 
+static bool only_mappable_for_reloc(unsigned int flags)
+{
+       return (flags & (EXEC_OBJECT_NEEDS_FENCE | __EXEC_OBJECT_NEEDS_MAP)) ==
+               __EXEC_OBJECT_NEEDS_MAP;
+}
+
 static int
 i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
                                struct intel_engine_cs *ring,
@@ -536,14 +592,21 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
        int ret;
 
        flags = 0;
-       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP)
-               flags |= PIN_GLOBAL | PIN_MAPPABLE;
-       if (entry->flags & EXEC_OBJECT_NEEDS_GTT)
-               flags |= PIN_GLOBAL;
-       if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
-               flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS;
+       if (!drm_mm_node_allocated(&vma->node)) {
+               if (entry->flags & __EXEC_OBJECT_NEEDS_MAP)
+                       flags |= PIN_GLOBAL | PIN_MAPPABLE;
+               if (entry->flags & EXEC_OBJECT_NEEDS_GTT)
+                       flags |= PIN_GLOBAL;
+               if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
+                       flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS;
+       }
 
        ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, flags);
+       if ((ret == -ENOSPC  || ret == -E2BIG) &&
+           only_mappable_for_reloc(entry->flags))
+               ret = i915_gem_object_pin(obj, vma->vm,
+                                         entry->alignment,
+                                         flags & ~(PIN_GLOBAL | PIN_MAPPABLE));
        if (ret)
                return ret;
 
@@ -605,13 +668,14 @@ eb_vma_misplaced(struct i915_vma *vma)
            vma->node.start & (entry->alignment - 1))
                return true;
 
-       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable)
-               return true;
-
        if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS &&
            vma->node.start < BATCH_OFFSET_BIAS)
                return true;
 
+       /* avoid costly ping-pong once a batch bo ended up non-mappable */
+       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable)
+               return !only_mappable_for_reloc(entry->flags);
+
        return false;
 }
 
@@ -1187,6 +1251,13 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
        if (ret)
                goto error;
 
+       if (ctx->ppgtt)
+               WARN(ctx->ppgtt->pd_dirty_rings & (1<<ring->id),
+                       "%s didn't clear reload\n", ring->name);
+       else if (dev_priv->mm.aliasing_ppgtt)
+               WARN(dev_priv->mm.aliasing_ppgtt->pd_dirty_rings &
+                       (1<<ring->id), "%s didn't clear reload\n", ring->name);
+
        instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
        instp_mask = I915_EXEC_CONSTANTS_MASK;
        switch (instp_mode) {
@@ -1476,7 +1547,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                goto err;
        }
 
-       if (i915_needs_cmd_parser(ring)) {
+       if (i915_needs_cmd_parser(ring) && args->batch_len) {
                batch_obj = i915_gem_execbuffer_parse(ring,
                                                      &shadow_exec_entry,
                                                      eb,
index 2034f7c..0239fbf 100644 (file)
@@ -67,8 +67,9 @@
  * i915_ggtt_view_type and struct i915_ggtt_view.
  *
  * A new flavour of core GEM functions which work with GGTT bound objects were
- * added with the _view suffix. They take the struct i915_ggtt_view parameter
- * encapsulating all metadata required to implement a view.
+ * added with the _ggtt_ infix, and sometimes with _view postfix to avoid
+ * renaming  in large amounts of code. They take the struct i915_ggtt_view
+ * parameter encapsulating all metadata required to implement a view.
  *
  * As a helper for callers which are only interested in the normal view,
  * globally const i915_ggtt_view_normal singleton instance exists. All old core
@@ -92,6 +93,9 @@
  */
 
 const struct i915_ggtt_view i915_ggtt_view_normal;
+const struct i915_ggtt_view i915_ggtt_view_rotated = {
+        .type = I915_GGTT_VIEW_ROTATED
+};
 
 static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv);
 static void chv_setup_private_ppat(struct drm_i915_private *dev_priv);
@@ -147,11 +151,11 @@ static void ppgtt_bind_vma(struct i915_vma *vma,
                           u32 flags);
 static void ppgtt_unbind_vma(struct i915_vma *vma);
 
-static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
-                                            enum i915_cache_level level,
-                                            bool valid)
+static inline gen8_pte_t gen8_pte_encode(dma_addr_t addr,
+                                        enum i915_cache_level level,
+                                        bool valid)
 {
-       gen8_gtt_pte_t pte = valid ? _PAGE_PRESENT | _PAGE_RW : 0;
+       gen8_pte_t pte = valid ? _PAGE_PRESENT | _PAGE_RW : 0;
        pte |= addr;
 
        switch (level) {
@@ -169,11 +173,11 @@ static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static inline gen8_ppgtt_pde_t gen8_pde_encode(struct drm_device *dev,
-                                            dma_addr_t addr,
-                                            enum i915_cache_level level)
+static inline gen8_pde_t gen8_pde_encode(struct drm_device *dev,
+                                         dma_addr_t addr,
+                                         enum i915_cache_level level)
 {
-       gen8_ppgtt_pde_t pde = _PAGE_PRESENT | _PAGE_RW;
+       gen8_pde_t pde = _PAGE_PRESENT | _PAGE_RW;
        pde |= addr;
        if (level != I915_CACHE_NONE)
                pde |= PPAT_CACHED_PDE_INDEX;
@@ -182,11 +186,11 @@ static inline gen8_ppgtt_pde_t gen8_pde_encode(struct drm_device *dev,
        return pde;
 }
 
-static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid, u32 unused)
+static gen6_pte_t snb_pte_encode(dma_addr_t addr,
+                                enum i915_cache_level level,
+                                bool valid, u32 unused)
 {
-       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
+       gen6_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -204,11 +208,11 @@ static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid, u32 unused)
+static gen6_pte_t ivb_pte_encode(dma_addr_t addr,
+                                enum i915_cache_level level,
+                                bool valid, u32 unused)
 {
-       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
+       gen6_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -228,11 +232,11 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid, u32 flags)
+static gen6_pte_t byt_pte_encode(dma_addr_t addr,
+                                enum i915_cache_level level,
+                                bool valid, u32 flags)
 {
-       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
+       gen6_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        if (!(flags & PTE_READ_ONLY))
@@ -244,11 +248,11 @@ static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid, u32 unused)
+static gen6_pte_t hsw_pte_encode(dma_addr_t addr,
+                                enum i915_cache_level level,
+                                bool valid, u32 unused)
 {
-       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
+       gen6_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
 
        if (level != I915_CACHE_NONE)
@@ -257,11 +261,11 @@ static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
-                                     enum i915_cache_level level,
-                                     bool valid, u32 unused)
+static gen6_pte_t iris_pte_encode(dma_addr_t addr,
+                                 enum i915_cache_level level,
+                                 bool valid, u32 unused)
 {
-       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
+       gen6_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -278,29 +282,91 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static void unmap_and_free_pt(struct i915_page_table_entry *pt, struct drm_device *dev)
+#define i915_dma_unmap_single(px, dev) \
+       __i915_dma_unmap_single((px)->daddr, dev)
+
+static inline void __i915_dma_unmap_single(dma_addr_t daddr,
+                                       struct drm_device *dev)
+{
+       struct device *device = &dev->pdev->dev;
+
+       dma_unmap_page(device, daddr, 4096, PCI_DMA_BIDIRECTIONAL);
+}
+
+/**
+ * i915_dma_map_single() - Create a dma mapping for a page table/dir/etc.
+ * @px:        Page table/dir/etc to get a DMA map for
+ * @dev:       drm device
+ *
+ * Page table allocations are unified across all gens. They always require a
+ * single 4k allocation, as well as a DMA mapping. If we keep the structs
+ * symmetric here, the simple macro covers us for every page table type.
+ *
+ * Return: 0 if success.
+ */
+#define i915_dma_map_single(px, dev) \
+       i915_dma_map_page_single((px)->page, (dev), &(px)->daddr)
+
+static inline int i915_dma_map_page_single(struct page *page,
+                                          struct drm_device *dev,
+                                          dma_addr_t *daddr)
+{
+       struct device *device = &dev->pdev->dev;
+
+       *daddr = dma_map_page(device, page, 0, 4096, PCI_DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(device, *daddr))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void unmap_and_free_pt(struct i915_page_table_entry *pt,
+                              struct drm_device *dev)
 {
        if (WARN_ON(!pt->page))
                return;
+
+       i915_dma_unmap_single(pt, dev);
        __free_page(pt->page);
+       kfree(pt->used_ptes);
        kfree(pt);
 }
 
 static struct i915_page_table_entry *alloc_pt_single(struct drm_device *dev)
 {
        struct i915_page_table_entry *pt;
+       const size_t count = INTEL_INFO(dev)->gen >= 8 ?
+               GEN8_PTES : GEN6_PTES;
+       int ret = -ENOMEM;
 
        pt = kzalloc(sizeof(*pt), GFP_KERNEL);
        if (!pt)
                return ERR_PTR(-ENOMEM);
 
-       pt->page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-       if (!pt->page) {
-               kfree(pt);
-               return ERR_PTR(-ENOMEM);
-       }
+       pt->used_ptes = kcalloc(BITS_TO_LONGS(count), sizeof(*pt->used_ptes),
+                               GFP_KERNEL);
+
+       if (!pt->used_ptes)
+               goto fail_bitmap;
+
+       pt->page = alloc_page(GFP_KERNEL);
+       if (!pt->page)
+               goto fail_page;
+
+       ret = i915_dma_map_single(pt, dev);
+       if (ret)
+               goto fail_dma;
 
        return pt;
+
+fail_dma:
+       __free_page(pt->page);
+fail_page:
+       kfree(pt->used_ptes);
+fail_bitmap:
+       kfree(pt);
+
+       return ERR_PTR(ret);
 }
 
 /**
@@ -318,12 +384,12 @@ static struct i915_page_table_entry *alloc_pt_single(struct drm_device *dev)
  * Return: 0 if allocation succeeded.
  */
 static int alloc_pt_range(struct i915_page_directory_entry *pd, uint16_t pde, size_t count,
-                 struct drm_device *dev)
+                         struct drm_device *dev)
 {
        int i, ret;
 
        /* 512 is the max page tables per page_directory on any platform. */
-       if (WARN_ON(pde + count > GEN6_PPGTT_PD_ENTRIES))
+       if (WARN_ON(pde + count > I915_PDES))
                return -EINVAL;
 
        for (i = pde; i < pde + count; i++) {
@@ -401,7 +467,7 @@ static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
        int i, ret;
 
        /* bit of a hack to find the actual last used pd */
-       int used_pd = ppgtt->num_pd_entries / GEN8_PDES_PER_PAGE;
+       int used_pd = ppgtt->num_pd_entries / I915_PDES;
 
        for (i = used_pd - 1; i >= 0; i--) {
                dma_addr_t addr = ppgtt->pdp.page_directory[i]->daddr;
@@ -420,7 +486,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
-       gen8_gtt_pte_t *pt_vaddr, scratch_pte;
+       gen8_pte_t *pt_vaddr, scratch_pte;
        unsigned pdpe = start >> GEN8_PDPE_SHIFT & GEN8_PDPE_MASK;
        unsigned pde = start >> GEN8_PDE_SHIFT & GEN8_PDE_MASK;
        unsigned pte = start >> GEN8_PTE_SHIFT & GEN8_PTE_MASK;
@@ -451,8 +517,8 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
                page_table = pt->page;
 
                last_pte = pte + num_entries;
-               if (last_pte > GEN8_PTES_PER_PAGE)
-                       last_pte = GEN8_PTES_PER_PAGE;
+               if (last_pte > GEN8_PTES)
+                       last_pte = GEN8_PTES;
 
                pt_vaddr = kmap_atomic(page_table);
 
@@ -466,7 +532,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
                kunmap_atomic(pt_vaddr);
 
                pte = 0;
-               if (++pde == GEN8_PDES_PER_PAGE) {
+               if (++pde == I915_PDES) {
                        pdpe++;
                        pde = 0;
                }
@@ -480,7 +546,7 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
-       gen8_gtt_pte_t *pt_vaddr;
+       gen8_pte_t *pt_vaddr;
        unsigned pdpe = start >> GEN8_PDPE_SHIFT & GEN8_PDPE_MASK;
        unsigned pde = start >> GEN8_PDE_SHIFT & GEN8_PDE_MASK;
        unsigned pte = start >> GEN8_PTE_SHIFT & GEN8_PTE_MASK;
@@ -503,12 +569,12 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
                pt_vaddr[pte] =
                        gen8_pte_encode(sg_page_iter_dma_address(&sg_iter),
                                        cache_level, true);
-               if (++pte == GEN8_PTES_PER_PAGE) {
+               if (++pte == GEN8_PTES) {
                        if (!HAS_LLC(ppgtt->base.dev))
                                drm_clflush_virt_range(pt_vaddr, PAGE_SIZE);
                        kunmap_atomic(pt_vaddr);
                        pt_vaddr = NULL;
-                       if (++pde == GEN8_PDES_PER_PAGE) {
+                       if (++pde == I915_PDES) {
                                pdpe++;
                                pde = 0;
                        }
@@ -529,7 +595,7 @@ static void gen8_free_page_tables(struct i915_page_directory_entry *pd, struct d
        if (!pd->page)
                return;
 
-       for (i = 0; i < GEN8_PDES_PER_PAGE; i++) {
+       for (i = 0; i < I915_PDES; i++) {
                if (WARN_ON(!pd->page_table[i]))
                        continue;
 
@@ -565,7 +631,7 @@ static void gen8_ppgtt_unmap_pages(struct i915_hw_ppgtt *ppgtt)
                pci_unmap_page(hwdev, ppgtt->pdp.page_directory[i]->daddr, PAGE_SIZE,
                               PCI_DMA_BIDIRECTIONAL);
 
-               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
+               for (j = 0; j < I915_PDES; j++) {
                        struct i915_page_directory_entry *pd = ppgtt->pdp.page_directory[i];
                        struct i915_page_table_entry *pt;
                        dma_addr_t addr;
@@ -598,7 +664,7 @@ static int gen8_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt)
 
        for (i = 0; i < ppgtt->num_pd_pages; i++) {
                ret = alloc_pt_range(ppgtt->pdp.page_directory[i],
-                                    0, GEN8_PDES_PER_PAGE, ppgtt->base.dev);
+                                    0, I915_PDES, ppgtt->base.dev);
                if (ret)
                        goto unwind_out;
        }
@@ -648,7 +714,7 @@ static int gen8_ppgtt_alloc(struct i915_hw_ppgtt *ppgtt,
        if (ret)
                goto err_out;
 
-       ppgtt->num_pd_entries = max_pdp * GEN8_PDES_PER_PAGE;
+       ppgtt->num_pd_entries = max_pdp * I915_PDES;
 
        return 0;
 
@@ -697,7 +763,7 @@ static int gen8_ppgtt_setup_page_tables(struct i915_hw_ppgtt *ppgtt,
        return 0;
 }
 
-/**
+/*
  * GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers
  * with a net effect resembling a 2-level page table in normal x86 terms. Each
  * PDP represents 1GB of memory 4 * 512 * 512 * 4096 = 4GB legacy 32b address
@@ -710,7 +776,7 @@ static int gen8_ppgtt_setup_page_tables(struct i915_hw_ppgtt *ppgtt,
 static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
 {
        const int max_pdp = DIV_ROUND_UP(size, 1 << 30);
-       const int min_pt_pages = GEN8_PDES_PER_PAGE * max_pdp;
+       const int min_pt_pages = I915_PDES * max_pdp;
        int i, j, ret;
 
        if (size % (1<<30))
@@ -733,7 +799,7 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
                if (ret)
                        goto bail;
 
-               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
+               for (j = 0; j < I915_PDES; j++) {
                        ret = gen8_ppgtt_setup_page_tables(ppgtt, i, j);
                        if (ret)
                                goto bail;
@@ -750,9 +816,9 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
         */
        for (i = 0; i < GEN8_LEGACY_PDPES; i++) {
                struct i915_page_directory_entry *pd = ppgtt->pdp.page_directory[i];
-               gen8_ppgtt_pde_t *pd_vaddr;
+               gen8_pde_t *pd_vaddr;
                pd_vaddr = kmap_atomic(ppgtt->pdp.page_directory[i]->page);
-               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
+               for (j = 0; j < I915_PDES; j++) {
                        struct i915_page_table_entry *pt = pd->page_table[j];
                        dma_addr_t addr = pt->daddr;
                        pd_vaddr[j] = gen8_pde_encode(ppgtt->base.dev, addr,
@@ -770,11 +836,11 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
        ppgtt->base.start = 0;
 
        /* This is the area that we advertise as usable for the caller */
-       ppgtt->base.total = max_pdp * GEN8_PDES_PER_PAGE * GEN8_PTES_PER_PAGE * PAGE_SIZE;
+       ppgtt->base.total = max_pdp * I915_PDES * GEN8_PTES * PAGE_SIZE;
 
        /* Set all ptes to a valid scratch page. Also above requested space */
        ppgtt->base.clear_range(&ppgtt->base, 0,
-                               ppgtt->num_pd_pages * GEN8_PTES_PER_PAGE * PAGE_SIZE,
+                               ppgtt->num_pd_pages * GEN8_PTES * PAGE_SIZE,
                                true);
 
        DRM_DEBUG_DRIVER("Allocated %d pages for page directories (%d wasted)\n",
@@ -794,22 +860,22 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
 {
        struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
        struct i915_address_space *vm = &ppgtt->base;
-       gen6_gtt_pte_t __iomem *pd_addr;
-       gen6_gtt_pte_t scratch_pte;
+       gen6_pte_t __iomem *pd_addr;
+       gen6_pte_t scratch_pte;
        uint32_t pd_entry;
        int pte, pde;
 
        scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0);
 
-       pd_addr = (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm +
-               ppgtt->pd.pd_offset / sizeof(gen6_gtt_pte_t);
+       pd_addr = (gen6_pte_t __iomem *)dev_priv->gtt.gsm +
+               ppgtt->pd.pd_offset / sizeof(gen6_pte_t);
 
        seq_printf(m, "  VM %p (pd_offset %x-%x):\n", vm,
                   ppgtt->pd.pd_offset,
                   ppgtt->pd.pd_offset + ppgtt->num_pd_entries);
        for (pde = 0; pde < ppgtt->num_pd_entries; pde++) {
                u32 expected;
-               gen6_gtt_pte_t *pt_vaddr;
+               gen6_pte_t *pt_vaddr;
                dma_addr_t pt_addr = ppgtt->pd.page_table[pde]->daddr;
                pd_entry = readl(pd_addr + pde);
                expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID);
@@ -822,9 +888,9 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
                seq_printf(m, "\tPDE: %x\n", pd_entry);
 
                pt_vaddr = kmap_atomic(ppgtt->pd.page_table[pde]->page);
-               for (pte = 0; pte < I915_PPGTT_PT_ENTRIES; pte+=4) {
+               for (pte = 0; pte < GEN6_PTES; pte+=4) {
                        unsigned long va =
-                               (pde * PAGE_SIZE * I915_PPGTT_PT_ENTRIES) +
+                               (pde * PAGE_SIZE * GEN6_PTES) +
                                (pte * PAGE_SIZE);
                        int i;
                        bool found = false;
@@ -847,26 +913,36 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
        }
 }
 
-static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
+/* Write pde (index) from the page directory @pd to the page table @pt */
+static void gen6_write_pde(struct i915_page_directory_entry *pd,
+                           const int pde, struct i915_page_table_entry *pt)
 {
-       struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
-       gen6_gtt_pte_t __iomem *pd_addr;
-       uint32_t pd_entry;
-       int i;
+       /* Caller needs to make sure the write completes if necessary */
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(pd, struct i915_hw_ppgtt, pd);
+       u32 pd_entry;
 
-       WARN_ON(ppgtt->pd.pd_offset & 0x3f);
-       pd_addr = (gen6_gtt_pte_t __iomem*)dev_priv->gtt.gsm +
-               ppgtt->pd.pd_offset / sizeof(gen6_gtt_pte_t);
-       for (i = 0; i < ppgtt->num_pd_entries; i++) {
-               dma_addr_t pt_addr;
+       pd_entry = GEN6_PDE_ADDR_ENCODE(pt->daddr);
+       pd_entry |= GEN6_PDE_VALID;
 
-               pt_addr = ppgtt->pd.page_table[i]->daddr;
-               pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
-               pd_entry |= GEN6_PDE_VALID;
+       writel(pd_entry, ppgtt->pd_addr + pde);
+}
 
-               writel(pd_entry, pd_addr + i);
-       }
-       readl(pd_addr);
+/* Write all the page tables found in the ppgtt structure to incrementing page
+ * directories. */
+static void gen6_write_page_range(struct drm_i915_private *dev_priv,
+                                 struct i915_page_directory_entry *pd,
+                                 uint32_t start, uint32_t length)
+{
+       struct i915_page_table_entry *pt;
+       uint32_t pde, temp;
+
+       gen6_for_each_pde(pt, pd, start, length, temp, pde)
+               gen6_write_pde(pd, pde, pt);
+
+       /* Make sure write is complete before other code can use this page
+        * table. Also require for WC mapped PTEs */
+       readl(dev_priv->gtt.gsm);
 }
 
 static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt)
@@ -1022,19 +1098,19 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
-       gen6_gtt_pte_t *pt_vaddr, scratch_pte;
+       gen6_pte_t *pt_vaddr, scratch_pte;
        unsigned first_entry = start >> PAGE_SHIFT;
        unsigned num_entries = length >> PAGE_SHIFT;
-       unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
-       unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+       unsigned act_pt = first_entry / GEN6_PTES;
+       unsigned first_pte = first_entry % GEN6_PTES;
        unsigned last_pte, i;
 
        scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0);
 
        while (num_entries) {
                last_pte = first_pte + num_entries;
-               if (last_pte > I915_PPGTT_PT_ENTRIES)
-                       last_pte = I915_PPGTT_PT_ENTRIES;
+               if (last_pte > GEN6_PTES)
+                       last_pte = GEN6_PTES;
 
                pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->page);
 
@@ -1056,10 +1132,10 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
-       gen6_gtt_pte_t *pt_vaddr;
+       gen6_pte_t *pt_vaddr;
        unsigned first_entry = start >> PAGE_SHIFT;
-       unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
-       unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+       unsigned act_pt = first_entry / GEN6_PTES;
+       unsigned act_pte = first_entry % GEN6_PTES;
        struct sg_page_iter sg_iter;
 
        pt_vaddr = NULL;
@@ -1071,7 +1147,7 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                        vm->pte_encode(sg_page_iter_dma_address(&sg_iter),
                                       cache_level, true, flags);
 
-               if (++act_pte == I915_PPGTT_PT_ENTRIES) {
+               if (++act_pte == GEN6_PTES) {
                        kunmap_atomic(pt_vaddr);
                        pt_vaddr = NULL;
                        act_pt++;
@@ -1082,23 +1158,133 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                kunmap_atomic(pt_vaddr);
 }
 
-static void gen6_ppgtt_unmap_pages(struct i915_hw_ppgtt *ppgtt)
+/* PDE TLBs are a pain invalidate pre GEN8. It requires a context reload. If we
+ * are switching between contexts with the same LRCA, we also must do a force
+ * restore.
+ */
+static inline void mark_tlbs_dirty(struct i915_hw_ppgtt *ppgtt)
 {
+       /* If current vm != vm, */
+       ppgtt->pd_dirty_rings = INTEL_INFO(ppgtt->base.dev)->ring_mask;
+}
+
+static void gen6_initialize_pt(struct i915_address_space *vm,
+               struct i915_page_table_entry *pt)
+{
+       gen6_pte_t *pt_vaddr, scratch_pte;
        int i;
 
-       for (i = 0; i < ppgtt->num_pd_entries; i++)
-               pci_unmap_page(ppgtt->base.dev->pdev,
-                              ppgtt->pd.page_table[i]->daddr,
-                              4096, PCI_DMA_BIDIRECTIONAL);
+       WARN_ON(vm->scratch.addr == 0);
+
+       scratch_pte = vm->pte_encode(vm->scratch.addr,
+                       I915_CACHE_LLC, true, 0);
+
+       pt_vaddr = kmap_atomic(pt->page);
+
+       for (i = 0; i < GEN6_PTES; i++)
+               pt_vaddr[i] = scratch_pte;
+
+       kunmap_atomic(pt_vaddr);
+}
+
+static int gen6_alloc_va_range(struct i915_address_space *vm,
+                              uint64_t start, uint64_t length)
+{
+       DECLARE_BITMAP(new_page_tables, I915_PDES);
+       struct drm_device *dev = vm->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_hw_ppgtt *ppgtt =
+                               container_of(vm, struct i915_hw_ppgtt, base);
+       struct i915_page_table_entry *pt;
+       const uint32_t start_save = start, length_save = length;
+       uint32_t pde, temp;
+       int ret;
+
+       WARN_ON(upper_32_bits(start));
+
+       bitmap_zero(new_page_tables, I915_PDES);
+
+       /* The allocation is done in two stages so that we can bail out with
+        * minimal amount of pain. The first stage finds new page tables that
+        * need allocation. The second stage marks use ptes within the page
+        * tables.
+        */
+       gen6_for_each_pde(pt, &ppgtt->pd, start, length, temp, pde) {
+               if (pt != ppgtt->scratch_pt) {
+                       WARN_ON(bitmap_empty(pt->used_ptes, GEN6_PTES));
+                       continue;
+               }
+
+               /* We've already allocated a page table */
+               WARN_ON(!bitmap_empty(pt->used_ptes, GEN6_PTES));
+
+               pt = alloc_pt_single(dev);
+               if (IS_ERR(pt)) {
+                       ret = PTR_ERR(pt);
+                       goto unwind_out;
+               }
+
+               gen6_initialize_pt(vm, pt);
+
+               ppgtt->pd.page_table[pde] = pt;
+               set_bit(pde, new_page_tables);
+               trace_i915_page_table_entry_alloc(vm, pde, start, GEN6_PDE_SHIFT);
+       }
+
+       start = start_save;
+       length = length_save;
+
+       gen6_for_each_pde(pt, &ppgtt->pd, start, length, temp, pde) {
+               DECLARE_BITMAP(tmp_bitmap, GEN6_PTES);
+
+               bitmap_zero(tmp_bitmap, GEN6_PTES);
+               bitmap_set(tmp_bitmap, gen6_pte_index(start),
+                          gen6_pte_count(start, length));
+
+               if (test_and_clear_bit(pde, new_page_tables))
+                       gen6_write_pde(&ppgtt->pd, pde, pt);
+
+               trace_i915_page_table_entry_map(vm, pde, pt,
+                                        gen6_pte_index(start),
+                                        gen6_pte_count(start, length),
+                                        GEN6_PTES);
+               bitmap_or(pt->used_ptes, tmp_bitmap, pt->used_ptes,
+                               GEN6_PTES);
+       }
+
+       WARN_ON(!bitmap_empty(new_page_tables, I915_PDES));
+
+       /* Make sure write is complete before other code can use this page
+        * table. Also require for WC mapped PTEs */
+       readl(dev_priv->gtt.gsm);
+
+       mark_tlbs_dirty(ppgtt);
+       return 0;
+
+unwind_out:
+       for_each_set_bit(pde, new_page_tables, I915_PDES) {
+               struct i915_page_table_entry *pt = ppgtt->pd.page_table[pde];
+
+               ppgtt->pd.page_table[pde] = ppgtt->scratch_pt;
+               unmap_and_free_pt(pt, vm->dev);
+       }
+
+       mark_tlbs_dirty(ppgtt);
+       return ret;
 }
 
 static void gen6_ppgtt_free(struct i915_hw_ppgtt *ppgtt)
 {
        int i;
 
-       for (i = 0; i < ppgtt->num_pd_entries; i++)
-               unmap_and_free_pt(ppgtt->pd.page_table[i], ppgtt->base.dev);
+       for (i = 0; i < ppgtt->num_pd_entries; i++) {
+               struct i915_page_table_entry *pt = ppgtt->pd.page_table[i];
 
+               if (pt != ppgtt->scratch_pt)
+                       unmap_and_free_pt(ppgtt->pd.page_table[i], ppgtt->base.dev);
+       }
+
+       unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev);
        unmap_and_free_pd(&ppgtt->pd);
 }
 
@@ -1109,7 +1295,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
 
        drm_mm_remove_node(&ppgtt->node);
 
-       gen6_ppgtt_unmap_pages(ppgtt);
        gen6_ppgtt_free(ppgtt);
 }
 
@@ -1125,6 +1310,12 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt)
         * size. We allocate at the top of the GTT to avoid fragmentation.
         */
        BUG_ON(!drm_mm_initialized(&dev_priv->gtt.base.mm));
+       ppgtt->scratch_pt = alloc_pt_single(ppgtt->base.dev);
+       if (IS_ERR(ppgtt->scratch_pt))
+               return PTR_ERR(ppgtt->scratch_pt);
+
+       gen6_initialize_pt(&ppgtt->base, ppgtt->scratch_pt);
+
 alloc:
        ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm,
                                                  &ppgtt->node, GEN6_PD_SIZE,
@@ -1138,66 +1329,43 @@ alloc:
                                               0, dev_priv->gtt.base.total,
                                               0);
                if (ret)
-                       return ret;
+                       goto err_out;
 
                retried = true;
                goto alloc;
        }
 
        if (ret)
-               return ret;
+               goto err_out;
+
 
        if (ppgtt->node.start < dev_priv->gtt.mappable_end)
                DRM_DEBUG("Forced to use aperture for PDEs\n");
 
-       ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES;
+       ppgtt->num_pd_entries = I915_PDES;
        return 0;
+
+err_out:
+       unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev);
+       return ret;
 }
 
 static int gen6_ppgtt_alloc(struct i915_hw_ppgtt *ppgtt)
 {
-       int ret;
-
-       ret = gen6_ppgtt_allocate_page_directories(ppgtt);
-       if (ret)
-               return ret;
-
-       ret = alloc_pt_range(&ppgtt->pd, 0, ppgtt->num_pd_entries,
-                       ppgtt->base.dev);
-
-       if (ret) {
-               drm_mm_remove_node(&ppgtt->node);
-               return ret;
-       }
-
-       return 0;
+       return gen6_ppgtt_allocate_page_directories(ppgtt);
 }
 
-static int gen6_ppgtt_setup_page_tables(struct i915_hw_ppgtt *ppgtt)
+static void gen6_scratch_va_range(struct i915_hw_ppgtt *ppgtt,
+                                 uint64_t start, uint64_t length)
 {
-       struct drm_device *dev = ppgtt->base.dev;
-       int i;
-
-       for (i = 0; i < ppgtt->num_pd_entries; i++) {
-               struct page *page;
-               dma_addr_t pt_addr;
-
-               page = ppgtt->pd.page_table[i]->page;
-               pt_addr = pci_map_page(dev->pdev, page, 0, 4096,
-                                      PCI_DMA_BIDIRECTIONAL);
-
-               if (pci_dma_mapping_error(dev->pdev, pt_addr)) {
-                       gen6_ppgtt_unmap_pages(ppgtt);
-                       return -EIO;
-               }
+       struct i915_page_table_entry *unused;
+       uint32_t pde, temp;
 
-               ppgtt->pd.page_table[i]->daddr = pt_addr;
-       }
-
-       return 0;
+       gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde)
+               ppgtt->pd.page_table[pde] = ppgtt->scratch_pt;
 }
 
-static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
+static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt, bool aliasing)
 {
        struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1220,36 +1388,50 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
        if (ret)
                return ret;
 
-       ret = gen6_ppgtt_setup_page_tables(ppgtt);
-       if (ret) {
-               gen6_ppgtt_free(ppgtt);
-               return ret;
+       if (aliasing) {
+               /* preallocate all pts */
+               ret = alloc_pt_range(&ppgtt->pd, 0, ppgtt->num_pd_entries,
+                               ppgtt->base.dev);
+
+               if (ret) {
+                       gen6_ppgtt_cleanup(&ppgtt->base);
+                       return ret;
+               }
        }
 
+       ppgtt->base.allocate_va_range = gen6_alloc_va_range;
        ppgtt->base.clear_range = gen6_ppgtt_clear_range;
        ppgtt->base.insert_entries = gen6_ppgtt_insert_entries;
        ppgtt->base.cleanup = gen6_ppgtt_cleanup;
        ppgtt->base.start = 0;
-       ppgtt->base.total = ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES * PAGE_SIZE;
+       ppgtt->base.total = ppgtt->num_pd_entries * GEN6_PTES * PAGE_SIZE;
        ppgtt->debug_dump = gen6_dump_ppgtt;
 
        ppgtt->pd.pd_offset =
-               ppgtt->node.start / PAGE_SIZE * sizeof(gen6_gtt_pte_t);
+               ppgtt->node.start / PAGE_SIZE * sizeof(gen6_pte_t);
+
+       ppgtt->pd_addr = (gen6_pte_t __iomem *)dev_priv->gtt.gsm +
+               ppgtt->pd.pd_offset / sizeof(gen6_pte_t);
+
+       if (aliasing)
+               ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true);
+       else
+               gen6_scratch_va_range(ppgtt, 0, ppgtt->base.total);
 
-       ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true);
+       gen6_write_page_range(dev_priv, &ppgtt->pd, 0, ppgtt->base.total);
 
        DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n",
                         ppgtt->node.size >> 20,
                         ppgtt->node.start / PAGE_SIZE);
 
-       gen6_write_pdes(ppgtt);
        DRM_DEBUG("Adding PPGTT at offset %x\n",
                  ppgtt->pd.pd_offset << 10);
 
        return 0;
 }
 
-static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
+static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt,
+               bool aliasing)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -1257,7 +1439,7 @@ static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
        ppgtt->base.scratch = dev_priv->gtt.base.scratch;
 
        if (INTEL_INFO(dev)->gen < 8)
-               return gen6_ppgtt_init(ppgtt);
+               return gen6_ppgtt_init(ppgtt, aliasing);
        else
                return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
 }
@@ -1266,7 +1448,7 @@ int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret = 0;
 
-       ret = __hw_ppgtt_init(dev, ppgtt);
+       ret = __hw_ppgtt_init(dev, ppgtt, false);
        if (ret == 0) {
                kref_init(&ppgtt->ref);
                drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
@@ -1513,15 +1695,20 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
                return;
        }
 
-       list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
-               /* TODO: Perhaps it shouldn't be gen6 specific */
-               if (i915_is_ggtt(vm)) {
-                       if (dev_priv->mm.aliasing_ppgtt)
-                               gen6_write_pdes(dev_priv->mm.aliasing_ppgtt);
-                       continue;
-               }
+       if (USES_PPGTT(dev)) {
+               list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
+                       /* TODO: Perhaps it shouldn't be gen6 specific */
 
-               gen6_write_pdes(container_of(vm, struct i915_hw_ppgtt, base));
+                       struct i915_hw_ppgtt *ppgtt =
+                                       container_of(vm, struct i915_hw_ppgtt,
+                                                    base);
+
+                       if (i915_is_ggtt(vm))
+                               ppgtt = dev_priv->mm.aliasing_ppgtt;
+
+                       gen6_write_page_range(dev_priv, &ppgtt->pd,
+                                             0, ppgtt->base.total);
+               }
        }
 
        i915_ggtt_flush(dev_priv);
@@ -1540,7 +1727,7 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
        return 0;
 }
 
-static inline void gen8_set_pte(void __iomem *addr, gen8_gtt_pte_t pte)
+static inline void gen8_set_pte(void __iomem *addr, gen8_pte_t pte)
 {
 #ifdef writeq
        writeq(pte, addr);
@@ -1557,8 +1744,8 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
-       gen8_gtt_pte_t __iomem *gtt_entries =
-               (gen8_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
+       gen8_pte_t __iomem *gtt_entries =
+               (gen8_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
        struct sg_page_iter sg_iter;
        dma_addr_t addr = 0; /* shut up gcc */
@@ -1603,8 +1790,8 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
-       gen6_gtt_pte_t __iomem *gtt_entries =
-               (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
+       gen6_pte_t __iomem *gtt_entries =
+               (gen6_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
        struct sg_page_iter sg_iter;
        dma_addr_t addr = 0;
@@ -1642,8 +1829,8 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm,
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
        unsigned num_entries = length >> PAGE_SHIFT;
-       gen8_gtt_pte_t scratch_pte, __iomem *gtt_base =
-               (gen8_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
+       gen8_pte_t scratch_pte, __iomem *gtt_base =
+               (gen8_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
        const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
        int i;
 
@@ -1668,8 +1855,8 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
        unsigned num_entries = length >> PAGE_SHIFT;
-       gen6_gtt_pte_t scratch_pte, __iomem *gtt_base =
-               (gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
+       gen6_pte_t scratch_pte, __iomem *gtt_base =
+               (gen6_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
        const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
        int i;
 
@@ -1726,11 +1913,15 @@ static void ggtt_bind_vma(struct i915_vma *vma,
        struct drm_device *dev = vma->vm->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj = vma->obj;
+       struct sg_table *pages = obj->pages;
 
        /* Currently applicable only to VLV */
        if (obj->gt_ro)
                flags |= PTE_READ_ONLY;
 
+       if (i915_is_ggtt(vma->vm))
+               pages = vma->ggtt_view.pages;
+
        /* If there is no aliasing PPGTT, or the caller needs a global mapping,
         * or we have a global mapping already but the cacheability flags have
         * changed, set the global PTEs.
@@ -1745,7 +1936,7 @@ static void ggtt_bind_vma(struct i915_vma *vma,
        if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) {
                if (!(vma->bound & GLOBAL_BIND) ||
                    (cache_level != obj->cache_level)) {
-                       vma->vm->insert_entries(vma->vm, vma->ggtt_view.pages,
+                       vma->vm->insert_entries(vma->vm, pages,
                                                vma->node.start,
                                                cache_level, flags);
                        vma->bound |= GLOBAL_BIND;
@@ -1756,8 +1947,7 @@ static void ggtt_bind_vma(struct i915_vma *vma,
            (!(vma->bound & LOCAL_BIND) ||
             (cache_level != obj->cache_level))) {
                struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
-               appgtt->base.insert_entries(&appgtt->base,
-                                           vma->ggtt_view.pages,
+               appgtt->base.insert_entries(&appgtt->base, pages,
                                            vma->node.start,
                                            cache_level, flags);
                vma->bound |= LOCAL_BIND;
@@ -1893,9 +2083,11 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
                if (!ppgtt)
                        return -ENOMEM;
 
-               ret = __hw_ppgtt_init(dev, ppgtt);
-               if (ret != 0)
+               ret = __hw_ppgtt_init(dev, ppgtt, true);
+               if (ret) {
+                       kfree(ppgtt);
                        return ret;
+               }
 
                dev_priv->mm.aliasing_ppgtt = ppgtt;
        }
@@ -2181,7 +2373,7 @@ static int gen8_gmch_probe(struct drm_device *dev,
                gtt_size = gen8_get_total_gtt_size(snb_gmch_ctl);
        }
 
-       *gtt_total = (gtt_size / sizeof(gen8_gtt_pte_t)) << PAGE_SHIFT;
+       *gtt_total = (gtt_size / sizeof(gen8_pte_t)) << PAGE_SHIFT;
 
        if (IS_CHERRYVIEW(dev))
                chv_setup_private_ppat(dev_priv);
@@ -2226,7 +2418,7 @@ static int gen6_gmch_probe(struct drm_device *dev,
        *stolen = gen6_get_stolen_size(snb_gmch_ctl);
 
        gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl);
-       *gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT;
+       *gtt_total = (gtt_size / sizeof(gen6_pte_t)) << PAGE_SHIFT;
 
        ret = ggtt_probe_common(dev, gtt_size);
 
@@ -2331,11 +2523,16 @@ int i915_gem_gtt_init(struct drm_device *dev)
        return 0;
 }
 
-static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
-                                             struct i915_address_space *vm,
-                                             const struct i915_ggtt_view *view)
+static struct i915_vma *
+__i915_gem_vma_create(struct drm_i915_gem_object *obj,
+                     struct i915_address_space *vm,
+                     const struct i915_ggtt_view *ggtt_view)
 {
-       struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
+       struct i915_vma *vma;
+
+       if (WARN_ON(i915_is_ggtt(vm) != !!ggtt_view))
+               return ERR_PTR(-EINVAL);
+       vma = kzalloc(sizeof(*vma), GFP_KERNEL);
        if (vma == NULL)
                return ERR_PTR(-ENOMEM);
 
@@ -2344,10 +2541,11 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
        INIT_LIST_HEAD(&vma->exec_list);
        vma->vm = vm;
        vma->obj = obj;
-       vma->ggtt_view = *view;
 
        if (INTEL_INFO(vm->dev)->gen >= 6) {
                if (i915_is_ggtt(vm)) {
+                       vma->ggtt_view = *ggtt_view;
+
                        vma->unbind_vma = ggtt_unbind_vma;
                        vma->bind_vma = ggtt_bind_vma;
                } else {
@@ -2356,6 +2554,7 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
                }
        } else {
                BUG_ON(!i915_is_ggtt(vm));
+               vma->ggtt_view = *ggtt_view;
                vma->unbind_vma = i915_ggtt_unbind_vma;
                vma->bind_vma = i915_ggtt_bind_vma;
        }
@@ -2368,38 +2567,170 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
 }
 
 struct i915_vma *
-i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
-                                      struct i915_address_space *vm,
+i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
+                                 struct i915_address_space *vm)
+{
+       struct i915_vma *vma;
+
+       vma = i915_gem_obj_to_vma(obj, vm);
+       if (!vma)
+               vma = __i915_gem_vma_create(obj, vm,
+                                           i915_is_ggtt(vm) ? &i915_ggtt_view_normal : NULL);
+
+       return vma;
+}
+
+struct i915_vma *
+i915_gem_obj_lookup_or_create_ggtt_vma(struct drm_i915_gem_object *obj,
                                       const struct i915_ggtt_view *view)
 {
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
        struct i915_vma *vma;
 
-       vma = i915_gem_obj_to_vma_view(obj, vm, view);
+       if (WARN_ON(!view))
+               return ERR_PTR(-EINVAL);
+
+       vma = i915_gem_obj_to_ggtt_view(obj, view);
+
+       if (IS_ERR(vma))
+               return vma;
+
        if (!vma)
-               vma = __i915_gem_vma_create(obj, vm, view);
+               vma = __i915_gem_vma_create(obj, ggtt, view);
 
        return vma;
+
+}
+
+static void
+rotate_pages(dma_addr_t *in, unsigned int width, unsigned int height,
+            struct sg_table *st)
+{
+       unsigned int column, row;
+       unsigned int src_idx;
+       struct scatterlist *sg = st->sgl;
+
+       st->nents = 0;
+
+       for (column = 0; column < width; column++) {
+               src_idx = width * (height - 1) + column;
+               for (row = 0; row < height; row++) {
+                       st->nents++;
+                       /* We don't need the pages, but need to initialize
+                        * the entries so the sg list can be happily traversed.
+                        * The only thing we need are DMA addresses.
+                        */
+                       sg_set_page(sg, NULL, PAGE_SIZE, 0);
+                       sg_dma_address(sg) = in[src_idx];
+                       sg_dma_len(sg) = PAGE_SIZE;
+                       sg = sg_next(sg);
+                       src_idx -= width;
+               }
+       }
 }
 
-static inline
-int i915_get_vma_pages(struct i915_vma *vma)
+static struct sg_table *
+intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
+                         struct drm_i915_gem_object *obj)
 {
+       struct drm_device *dev = obj->base.dev;
+       struct intel_rotation_info *rot_info = &ggtt_view->rotation_info;
+       unsigned long size, pages, rot_pages;
+       struct sg_page_iter sg_iter;
+       unsigned long i;
+       dma_addr_t *page_addr_list;
+       struct sg_table *st;
+       unsigned int tile_pitch, tile_height;
+       unsigned int width_pages, height_pages;
+       int ret = -ENOMEM;
+
+       pages = obj->base.size / PAGE_SIZE;
+
+       /* Calculate tiling geometry. */
+       tile_height = intel_tile_height(dev, rot_info->pixel_format,
+                                       rot_info->fb_modifier);
+       tile_pitch = PAGE_SIZE / tile_height;
+       width_pages = DIV_ROUND_UP(rot_info->pitch, tile_pitch);
+       height_pages = DIV_ROUND_UP(rot_info->height, tile_height);
+       rot_pages = width_pages * height_pages;
+       size = rot_pages * PAGE_SIZE;
+
+       /* Allocate a temporary list of source pages for random access. */
+       page_addr_list = drm_malloc_ab(pages, sizeof(dma_addr_t));
+       if (!page_addr_list)
+               return ERR_PTR(ret);
+
+       /* Allocate target SG list. */
+       st = kmalloc(sizeof(*st), GFP_KERNEL);
+       if (!st)
+               goto err_st_alloc;
+
+       ret = sg_alloc_table(st, rot_pages, GFP_KERNEL);
+       if (ret)
+               goto err_sg_alloc;
+
+       /* Populate source page list from the object. */
+       i = 0;
+       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
+               page_addr_list[i] = sg_page_iter_dma_address(&sg_iter);
+               i++;
+       }
+
+       /* Rotate the pages. */
+       rotate_pages(page_addr_list, width_pages, height_pages, st);
+
+       DRM_DEBUG_KMS(
+                     "Created rotated page mapping for object size %lu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages).\n",
+                     size, rot_info->pitch, rot_info->height,
+                     rot_info->pixel_format, width_pages, height_pages,
+                     rot_pages);
+
+       drm_free_large(page_addr_list);
+
+       return st;
+
+err_sg_alloc:
+       kfree(st);
+err_st_alloc:
+       drm_free_large(page_addr_list);
+
+       DRM_DEBUG_KMS(
+                     "Failed to create rotated mapping for object size %lu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages)\n",
+                     size, ret, rot_info->pitch, rot_info->height,
+                     rot_info->pixel_format, width_pages, height_pages,
+                     rot_pages);
+       return ERR_PTR(ret);
+}
+
+static inline int
+i915_get_ggtt_vma_pages(struct i915_vma *vma)
+{
+       int ret = 0;
+
        if (vma->ggtt_view.pages)
                return 0;
 
        if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
                vma->ggtt_view.pages = vma->obj->pages;
+       else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
+               vma->ggtt_view.pages =
+                       intel_rotate_fb_obj_pages(&vma->ggtt_view, vma->obj);
        else
                WARN_ONCE(1, "GGTT view %u not implemented!\n",
                          vma->ggtt_view.type);
 
        if (!vma->ggtt_view.pages) {
-               DRM_ERROR("Failed to get pages for VMA view type %u!\n",
+               DRM_ERROR("Failed to get pages for GGTT view type %u!\n",
                          vma->ggtt_view.type);
-               return -EINVAL;
+               ret = -EINVAL;
+       } else if (IS_ERR(vma->ggtt_view.pages)) {
+               ret = PTR_ERR(vma->ggtt_view.pages);
+               vma->ggtt_view.pages = NULL;
+               DRM_ERROR("Failed to get pages for VMA view type %u (%d)!\n",
+                         vma->ggtt_view.type, ret);
        }
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -2415,10 +2746,12 @@ int i915_get_vma_pages(struct i915_vma *vma)
 int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
                  u32 flags)
 {
-       int ret = i915_get_vma_pages(vma);
+       if (i915_is_ggtt(vma->vm)) {
+               int ret = i915_get_ggtt_vma_pages(vma);
 
-       if (ret)
-               return ret;
+               if (ret)
+                       return ret;
+       }
 
        vma->bind_vma(vma, cache_level, flags);
 
index c9e93f5..fc03c99 100644 (file)
 
 struct drm_i915_file_private;
 
-typedef uint32_t gen6_gtt_pte_t;
-typedef uint64_t gen8_gtt_pte_t;
-typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
+typedef uint32_t gen6_pte_t;
+typedef uint64_t gen8_pte_t;
+typedef uint64_t gen8_pde_t;
 
 #define gtt_total_entries(gtt) ((gtt).base.total >> PAGE_SHIFT)
 
-#define I915_PPGTT_PT_ENTRIES          (PAGE_SIZE / sizeof(gen6_gtt_pte_t))
+
 /* gen6-hsw has bit 11-4 for physical addr bit 39-32 */
 #define GEN6_GTT_ADDR_ENCODE(addr)     ((addr) | (((addr) >> 28) & 0xff0))
 #define GEN6_PTE_ADDR_ENCODE(addr)     GEN6_GTT_ADDR_ENCODE(addr)
@@ -51,9 +51,16 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
 #define GEN6_PTE_UNCACHED              (1 << 1)
 #define GEN6_PTE_VALID                 (1 << 0)
 
-#define GEN6_PPGTT_PD_ENTRIES          512
-#define GEN6_PD_SIZE                   (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE)
+#define I915_PTES(pte_len)             (PAGE_SIZE / (pte_len))
+#define I915_PTE_MASK(pte_len)         (I915_PTES(pte_len) - 1)
+#define I915_PDES                      512
+#define I915_PDE_MASK                  (I915_PDES - 1)
+#define NUM_PTE(pde_shift)     (1 << (pde_shift - PAGE_SHIFT))
+
+#define GEN6_PTES                      I915_PTES(sizeof(gen6_pte_t))
+#define GEN6_PD_SIZE                   (I915_PDES * PAGE_SIZE)
 #define GEN6_PD_ALIGN                  (PAGE_SIZE * 16)
+#define GEN6_PDE_SHIFT                 22
 #define GEN6_PDE_VALID                 (1 << 0)
 
 #define GEN7_PTE_CACHE_L3_LLC          (3 << 1)
@@ -89,8 +96,7 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
 #define GEN8_PTE_SHIFT                 12
 #define GEN8_PTE_MASK                  0x1ff
 #define GEN8_LEGACY_PDPES              4
-#define GEN8_PTES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_gtt_pte_t))
-#define GEN8_PDES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t))
+#define GEN8_PTES                      I915_PTES(sizeof(gen8_pte_t))
 
 #define PPAT_UNCACHED_INDEX            (_PAGE_PWT | _PAGE_PCD)
 #define PPAT_CACHED_PDE_INDEX          0 /* WB LLC */
@@ -111,15 +117,28 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
 
 enum i915_ggtt_view_type {
        I915_GGTT_VIEW_NORMAL = 0,
+       I915_GGTT_VIEW_ROTATED
+};
+
+struct intel_rotation_info {
+       unsigned int height;
+       unsigned int pitch;
+       uint32_t pixel_format;
+       uint64_t fb_modifier;
 };
 
 struct i915_ggtt_view {
        enum i915_ggtt_view_type type;
 
        struct sg_table *pages;
+
+       union {
+               struct intel_rotation_info rotation_info;
+       };
 };
 
 extern const struct i915_ggtt_view i915_ggtt_view_normal;
+extern const struct i915_ggtt_view i915_ggtt_view_rotated;
 
 enum i915_cache_level;
 
@@ -190,6 +209,8 @@ struct i915_vma {
 struct i915_page_table_entry {
        struct page *page;
        dma_addr_t daddr;
+
+       unsigned long *used_ptes;
 };
 
 struct i915_page_directory_entry {
@@ -199,7 +220,7 @@ struct i915_page_directory_entry {
                dma_addr_t daddr;
        };
 
-       struct i915_page_table_entry *page_table[GEN6_PPGTT_PD_ENTRIES]; /* PDEs */
+       struct i915_page_table_entry *page_table[I915_PDES]; /* PDEs */
 };
 
 struct i915_page_directory_pointer_entry {
@@ -243,9 +264,12 @@ struct i915_address_space {
        struct list_head inactive_list;
 
        /* FIXME: Need a more generic return type */
-       gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid, u32 flags); /* Create a valid PTE */
+       gen6_pte_t (*pte_encode)(dma_addr_t addr,
+                                enum i915_cache_level level,
+                                bool valid, u32 flags); /* Create a valid PTE */
+       int (*allocate_va_range)(struct i915_address_space *vm,
+                                uint64_t start,
+                                uint64_t length);
        void (*clear_range)(struct i915_address_space *vm,
                            uint64_t start,
                            uint64_t length,
@@ -289,6 +313,7 @@ struct i915_hw_ppgtt {
        struct i915_address_space base;
        struct kref ref;
        struct drm_mm_node node;
+       unsigned long pd_dirty_rings;
        unsigned num_pd_entries;
        unsigned num_pd_pages; /* gen8+ */
        union {
@@ -296,14 +321,82 @@ struct i915_hw_ppgtt {
                struct i915_page_directory_entry pd;
        };
 
+       struct i915_page_table_entry *scratch_pt;
+
        struct drm_i915_file_private *file_priv;
 
+       gen6_pte_t __iomem *pd_addr;
+
        int (*enable)(struct i915_hw_ppgtt *ppgtt);
        int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
                         struct intel_engine_cs *ring);
        void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m);
 };
 
+/* For each pde iterates over every pde between from start until start + length.
+ * If start, and start+length are not perfectly divisible, the macro will round
+ * down, and up as needed. The macro modifies pde, start, and length. Dev is
+ * only used to differentiate shift values. Temp is temp.  On gen6/7, start = 0,
+ * and length = 2G effectively iterates over every PDE in the system.
+ *
+ * XXX: temp is not actually needed, but it saves doing the ALIGN operation.
+ */
+#define gen6_for_each_pde(pt, pd, start, length, temp, iter) \
+       for (iter = gen6_pde_index(start); \
+            pt = (pd)->page_table[iter], length > 0 && iter < I915_PDES; \
+            iter++, \
+            temp = ALIGN(start+1, 1 << GEN6_PDE_SHIFT) - start, \
+            temp = min_t(unsigned, temp, length), \
+            start += temp, length -= temp)
+
+static inline uint32_t i915_pte_index(uint64_t address, uint32_t pde_shift)
+{
+       const uint32_t mask = NUM_PTE(pde_shift) - 1;
+
+       return (address >> PAGE_SHIFT) & mask;
+}
+
+/* Helper to counts the number of PTEs within the given length. This count
+ * does not cross a page table boundary, so the max value would be
+ * GEN6_PTES for GEN6, and GEN8_PTES for GEN8.
+*/
+static inline uint32_t i915_pte_count(uint64_t addr, size_t length,
+                                     uint32_t pde_shift)
+{
+       const uint64_t mask = ~((1 << pde_shift) - 1);
+       uint64_t end;
+
+       WARN_ON(length == 0);
+       WARN_ON(offset_in_page(addr|length));
+
+       end = addr + length;
+
+       if ((addr & mask) != (end & mask))
+               return NUM_PTE(pde_shift) - i915_pte_index(addr, pde_shift);
+
+       return i915_pte_index(end, pde_shift) - i915_pte_index(addr, pde_shift);
+}
+
+static inline uint32_t i915_pde_index(uint64_t addr, uint32_t shift)
+{
+       return (addr >> shift) & I915_PDE_MASK;
+}
+
+static inline uint32_t gen6_pte_index(uint32_t addr)
+{
+       return i915_pte_index(addr, GEN6_PDE_SHIFT);
+}
+
+static inline size_t gen6_pte_count(uint32_t addr, uint32_t length)
+{
+       return i915_pte_count(addr, length, GEN6_PDE_SHIFT);
+}
+
+static inline uint32_t gen6_pde_index(uint32_t addr)
+{
+       return i915_pde_index(addr, GEN6_PDE_SHIFT);
+}
+
 int i915_gem_gtt_init(struct drm_device *dev);
 void i915_gem_init_global_gtt(struct drm_device *dev);
 void i915_global_gtt_cleanup(struct drm_device *dev);
@@ -332,4 +425,14 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev);
 int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj);
 void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj);
 
+static inline bool
+i915_ggtt_view_equal(const struct i915_ggtt_view *a,
+                     const struct i915_ggtt_view *b)
+{
+       if (WARN_ON(!a || !b))
+               return false;
+
+       return a->type == b->type;
+}
+
 #endif
diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c
new file mode 100644 (file)
index 0000000..f7929e7
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright Â© 2008-2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/oom.h>
+#include <linux/shmem_fs.h>
+#include <linux/slab.h>
+#include <linux/swap.h>
+#include <linux/pci.h>
+#include <linux/dma-buf.h>
+#include <drm/drmP.h>
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "i915_trace.h"
+
+static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
+{
+       if (!mutex_is_locked(mutex))
+               return false;
+
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
+       return mutex->owner == task;
+#else
+       /* Since UP may be pre-empted, we cannot assume that we own the lock */
+       return false;
+#endif
+}
+
+/**
+ * i915_gem_shrink - Shrink buffer object caches
+ * @dev_priv: i915 device
+ * @target: amount of memory to make available, in pages
+ * @flags: control flags for selecting cache types
+ *
+ * This function is the main interface to the shrinker. It will try to release
+ * up to @target pages of main memory backing storage from buffer objects.
+ * Selection of the specific caches can be done with @flags. This is e.g. useful
+ * when purgeable objects should be removed from caches preferentially.
+ *
+ * Note that it's not guaranteed that released amount is actually available as
+ * free system memory - the pages might still be in-used to due to other reasons
+ * (like cpu mmaps) or the mm core has reused them before we could grab them.
+ * Therefore code that needs to explicitly shrink buffer objects caches (e.g. to
+ * avoid deadlocks in memory reclaim) must fall back to i915_gem_shrink_all().
+ *
+ * Also note that any kind of pinning (both per-vma address space pins and
+ * backing storage pins at the buffer object level) result in the shrinker code
+ * having to skip the object.
+ *
+ * Returns:
+ * The number of pages of backing storage actually released.
+ */
+unsigned long
+i915_gem_shrink(struct drm_i915_private *dev_priv,
+               long target, unsigned flags)
+{
+       const struct {
+               struct list_head *list;
+               unsigned int bit;
+       } phases[] = {
+               { &dev_priv->mm.unbound_list, I915_SHRINK_UNBOUND },
+               { &dev_priv->mm.bound_list, I915_SHRINK_BOUND },
+               { NULL, 0 },
+       }, *phase;
+       unsigned long count = 0;
+
+       /*
+        * As we may completely rewrite the (un)bound list whilst unbinding
+        * (due to retiring requests) we have to strictly process only
+        * one element of the list at the time, and recheck the list
+        * on every iteration.
+        *
+        * In particular, we must hold a reference whilst removing the
+        * object as we may end up waiting for and/or retiring the objects.
+        * This might release the final reference (held by the active list)
+        * and result in the object being freed from under us. This is
+        * similar to the precautions the eviction code must take whilst
+        * removing objects.
+        *
+        * Also note that although these lists do not hold a reference to
+        * the object we can safely grab one here: The final object
+        * unreferencing and the bound_list are both protected by the
+        * dev->struct_mutex and so we won't ever be able to observe an
+        * object on the bound_list with a reference count equals 0.
+        */
+       for (phase = phases; phase->list; phase++) {
+               struct list_head still_in_list;
+
+               if ((flags & phase->bit) == 0)
+                       continue;
+
+               INIT_LIST_HEAD(&still_in_list);
+               while (count < target && !list_empty(phase->list)) {
+                       struct drm_i915_gem_object *obj;
+                       struct i915_vma *vma, *v;
+
+                       obj = list_first_entry(phase->list,
+                                              typeof(*obj), global_list);
+                       list_move_tail(&obj->global_list, &still_in_list);
+
+                       if (flags & I915_SHRINK_PURGEABLE &&
+                           obj->madv != I915_MADV_DONTNEED)
+                               continue;
+
+                       drm_gem_object_reference(&obj->base);
+
+                       /* For the unbound phase, this should be a no-op! */
+                       list_for_each_entry_safe(vma, v,
+                                                &obj->vma_list, vma_link)
+                               if (i915_vma_unbind(vma))
+                                       break;
+
+                       if (i915_gem_object_put_pages(obj) == 0)
+                               count += obj->base.size >> PAGE_SHIFT;
+
+                       drm_gem_object_unreference(&obj->base);
+               }
+               list_splice(&still_in_list, phase->list);
+       }
+
+       return count;
+}
+
+/**
+ * i915_gem_shrink - Shrink buffer object caches completely
+ * @dev_priv: i915 device
+ *
+ * This is a simple wraper around i915_gem_shrink() to aggressively shrink all
+ * caches completely. It also first waits for and retires all outstanding
+ * requests to also be able to release backing storage for active objects.
+ *
+ * This should only be used in code to intentionally quiescent the gpu or as a
+ * last-ditch effort when memory seems to have run out.
+ *
+ * Returns:
+ * The number of pages of backing storage actually released.
+ */
+unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv)
+{
+       i915_gem_evict_everything(dev_priv->dev);
+       return i915_gem_shrink(dev_priv, LONG_MAX,
+                              I915_SHRINK_BOUND | I915_SHRINK_UNBOUND);
+}
+
+static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock)
+{
+       if (!mutex_trylock(&dev->struct_mutex)) {
+               if (!mutex_is_locked_by(&dev->struct_mutex, current))
+                       return false;
+
+               if (to_i915(dev)->mm.shrinker_no_lock_stealing)
+                       return false;
+
+               *unlock = false;
+       } else
+               *unlock = true;
+
+       return true;
+}
+
+static int num_vma_bound(struct drm_i915_gem_object *obj)
+{
+       struct i915_vma *vma;
+       int count = 0;
+
+       list_for_each_entry(vma, &obj->vma_list, vma_link)
+               if (drm_mm_node_allocated(&vma->node))
+                       count++;
+
+       return count;
+}
+
+static unsigned long
+i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(shrinker, struct drm_i915_private, mm.shrinker);
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_i915_gem_object *obj;
+       unsigned long count;
+       bool unlock;
+
+       if (!i915_gem_shrinker_lock(dev, &unlock))
+               return 0;
+
+       count = 0;
+       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
+               if (obj->pages_pin_count == 0)
+                       count += obj->base.size >> PAGE_SHIFT;
+
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
+               if (!i915_gem_obj_is_pinned(obj) &&
+                   obj->pages_pin_count == num_vma_bound(obj))
+                       count += obj->base.size >> PAGE_SHIFT;
+       }
+
+       if (unlock)
+               mutex_unlock(&dev->struct_mutex);
+
+       return count;
+}
+
+static unsigned long
+i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(shrinker, struct drm_i915_private, mm.shrinker);
+       struct drm_device *dev = dev_priv->dev;
+       unsigned long freed;
+       bool unlock;
+
+       if (!i915_gem_shrinker_lock(dev, &unlock))
+               return SHRINK_STOP;
+
+       freed = i915_gem_shrink(dev_priv,
+                               sc->nr_to_scan,
+                               I915_SHRINK_BOUND |
+                               I915_SHRINK_UNBOUND |
+                               I915_SHRINK_PURGEABLE);
+       if (freed < sc->nr_to_scan)
+               freed += i915_gem_shrink(dev_priv,
+                                        sc->nr_to_scan - freed,
+                                        I915_SHRINK_BOUND |
+                                        I915_SHRINK_UNBOUND);
+       if (unlock)
+               mutex_unlock(&dev->struct_mutex);
+
+       return freed;
+}
+
+static int
+i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(nb, struct drm_i915_private, mm.oom_notifier);
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_i915_gem_object *obj;
+       unsigned long timeout = msecs_to_jiffies(5000) + 1;
+       unsigned long pinned, bound, unbound, freed_pages;
+       bool was_interruptible;
+       bool unlock;
+
+       while (!i915_gem_shrinker_lock(dev, &unlock) && --timeout) {
+               schedule_timeout_killable(1);
+               if (fatal_signal_pending(current))
+                       return NOTIFY_DONE;
+       }
+       if (timeout == 0) {
+               pr_err("Unable to purge GPU memory due lock contention.\n");
+               return NOTIFY_DONE;
+       }
+
+       was_interruptible = dev_priv->mm.interruptible;
+       dev_priv->mm.interruptible = false;
+
+       freed_pages = i915_gem_shrink_all(dev_priv);
+
+       dev_priv->mm.interruptible = was_interruptible;
+
+       /* Because we may be allocating inside our own driver, we cannot
+        * assert that there are no objects with pinned pages that are not
+        * being pointed to by hardware.
+        */
+       unbound = bound = pinned = 0;
+       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
+               if (!obj->base.filp) /* not backed by a freeable object */
+                       continue;
+
+               if (obj->pages_pin_count)
+                       pinned += obj->base.size;
+               else
+                       unbound += obj->base.size;
+       }
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
+               if (!obj->base.filp)
+                       continue;
+
+               if (obj->pages_pin_count)
+                       pinned += obj->base.size;
+               else
+                       bound += obj->base.size;
+       }
+
+       if (unlock)
+               mutex_unlock(&dev->struct_mutex);
+
+       if (freed_pages || unbound || bound)
+               pr_info("Purging GPU memory, %lu bytes freed, %lu bytes still pinned.\n",
+                       freed_pages << PAGE_SHIFT, pinned);
+       if (unbound || bound)
+               pr_err("%lu and %lu bytes still available in the "
+                      "bound and unbound GPU page lists.\n",
+                      bound, unbound);
+
+       *(unsigned long *)ptr += freed_pages;
+       return NOTIFY_DONE;
+}
+
+/**
+ * i915_gem_shrinker_init - Initialize i915 shrinker
+ * @dev_priv: i915 device
+ *
+ * This function registers and sets up the i915 shrinker and OOM handler.
+ */
+void i915_gem_shrinker_init(struct drm_i915_private *dev_priv)
+{
+       dev_priv->mm.shrinker.scan_objects = i915_gem_shrinker_scan;
+       dev_priv->mm.shrinker.count_objects = i915_gem_shrinker_count;
+       dev_priv->mm.shrinker.seeks = DEFAULT_SEEKS;
+       register_shrinker(&dev_priv->mm.shrinker);
+
+       dev_priv->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom;
+       register_oom_notifier(&dev_priv->mm.oom_notifier);
+}
index a982849..1d4e60d 100644 (file)
@@ -386,6 +386,11 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 
        if (INTEL_INFO(dev)->gen >= 6) {
                err_printf(m, "ERROR: 0x%08x\n", error->error);
+
+               if (INTEL_INFO(dev)->gen >= 8)
+                       err_printf(m, "FAULT_TLB_DATA: 0x%08x 0x%08x\n",
+                                  error->fault_data1, error->fault_data0);
+
                err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
        }
 
@@ -555,7 +560,14 @@ static void i915_error_state_free(struct kref *error_ref)
        }
 
        i915_error_object_free(error->semaphore_obj);
+
+       for (i = 0; i < error->vm_count; i++)
+               kfree(error->active_bo[i]);
+
        kfree(error->active_bo);
+       kfree(error->active_bo_count);
+       kfree(error->pinned_bo);
+       kfree(error->pinned_bo_count);
        kfree(error->overlay);
        kfree(error->display);
        kfree(error);
@@ -1164,6 +1176,11 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
        if (IS_GEN7(dev))
                error->err_int = I915_READ(GEN7_ERR_INT);
 
+       if (INTEL_INFO(dev)->gen >= 8) {
+               error->fault_data0 = I915_READ(GEN8_FAULT_TLB_DATA0);
+               error->fault_data1 = I915_READ(GEN8_FAULT_TLB_DATA1);
+       }
+
        if (IS_GEN6(dev)) {
                error->forcewake = I915_READ(FORCEWAKE);
                error->gab_ctl = I915_READ(GAB_CTL);
index 49ad5fb..14ecb4d 100644 (file)
@@ -277,6 +277,7 @@ void gen6_reset_rps_interrupts(struct drm_device *dev)
        I915_WRITE(reg, dev_priv->pm_rps_events);
        I915_WRITE(reg, dev_priv->pm_rps_events);
        POSTING_READ(reg);
+       dev_priv->rps.pm_iir = 0;
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
@@ -330,12 +331,10 @@ void gen6_disable_rps_interrupts(struct drm_device *dev)
        __gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
        I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) &
                                ~dev_priv->pm_rps_events);
-       I915_WRITE(gen6_pm_iir(dev_priv), dev_priv->pm_rps_events);
-       I915_WRITE(gen6_pm_iir(dev_priv), dev_priv->pm_rps_events);
-
-       dev_priv->rps.pm_iir = 0;
 
        spin_unlock_irq(&dev_priv->irq_lock);
+
+       synchronize_irq(dev->irq);
 }
 
 /**
@@ -997,129 +996,73 @@ static void notify_ring(struct drm_device *dev,
        wake_up_all(&ring->irq_queue);
 }
 
-static u32 vlv_c0_residency(struct drm_i915_private *dev_priv,
-                           struct intel_rps_ei *rps_ei)
+static void vlv_c0_read(struct drm_i915_private *dev_priv,
+                       struct intel_rps_ei *ei)
 {
-       u32 cz_ts, cz_freq_khz;
-       u32 render_count, media_count;
-       u32 elapsed_render, elapsed_media, elapsed_time;
-       u32 residency = 0;
-
-       cz_ts = vlv_punit_read(dev_priv, PUNIT_REG_CZ_TIMESTAMP);
-       cz_freq_khz = DIV_ROUND_CLOSEST(dev_priv->mem_freq * 1000, 4);
-
-       render_count = I915_READ(VLV_RENDER_C0_COUNT_REG);
-       media_count = I915_READ(VLV_MEDIA_C0_COUNT_REG);
-
-       if (rps_ei->cz_clock == 0) {
-               rps_ei->cz_clock = cz_ts;
-               rps_ei->render_c0 = render_count;
-               rps_ei->media_c0 = media_count;
-
-               return dev_priv->rps.cur_freq;
-       }
-
-       elapsed_time = cz_ts - rps_ei->cz_clock;
-       rps_ei->cz_clock = cz_ts;
+       ei->cz_clock = vlv_punit_read(dev_priv, PUNIT_REG_CZ_TIMESTAMP);
+       ei->render_c0 = I915_READ(VLV_RENDER_C0_COUNT);
+       ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT);
+}
 
-       elapsed_render = render_count - rps_ei->render_c0;
-       rps_ei->render_c0 = render_count;
+static bool vlv_c0_above(struct drm_i915_private *dev_priv,
+                        const struct intel_rps_ei *old,
+                        const struct intel_rps_ei *now,
+                        int threshold)
+{
+       u64 time, c0;
 
-       elapsed_media = media_count - rps_ei->media_c0;
-       rps_ei->media_c0 = media_count;
+       if (old->cz_clock == 0)
+               return false;
 
-       /* Convert all the counters into common unit of milli sec */
-       elapsed_time /= VLV_CZ_CLOCK_TO_MILLI_SEC;
-       elapsed_render /=  cz_freq_khz;
-       elapsed_media /= cz_freq_khz;
+       time = now->cz_clock - old->cz_clock;
+       time *= threshold * dev_priv->mem_freq;
 
-       /*
-        * Calculate overall C0 residency percentage
-        * only if elapsed time is non zero
+       /* Workload can be split between render + media, e.g. SwapBuffers
+        * being blitted in X after being rendered in mesa. To account for
+        * this we need to combine both engines into our activity counter.
         */
-       if (elapsed_time) {
-               residency =
-                       ((max(elapsed_render, elapsed_media) * 100)
-                               / elapsed_time);
-       }
+       c0 = now->render_c0 - old->render_c0;
+       c0 += now->media_c0 - old->media_c0;
+       c0 *= 100 * VLV_CZ_CLOCK_TO_MILLI_SEC * 4 / 1000;
 
-       return residency;
+       return c0 >= time;
 }
 
-/**
- * vlv_calc_delay_from_C0_counters - Increase/Decrease freq based on GPU
- * busy-ness calculated from C0 counters of render & media power wells
- * @dev_priv: DRM device private
- *
- */
-static int vlv_calc_delay_from_C0_counters(struct drm_i915_private *dev_priv)
+void gen6_rps_reset_ei(struct drm_i915_private *dev_priv)
 {
-       u32 residency_C0_up = 0, residency_C0_down = 0;
-       int new_delay, adj;
-
-       dev_priv->rps.ei_interrupt_count++;
-
-       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-
-
-       if (dev_priv->rps.up_ei.cz_clock == 0) {
-               vlv_c0_residency(dev_priv, &dev_priv->rps.up_ei);
-               vlv_c0_residency(dev_priv, &dev_priv->rps.down_ei);
-               return dev_priv->rps.cur_freq;
-       }
+       vlv_c0_read(dev_priv, &dev_priv->rps.down_ei);
+       dev_priv->rps.up_ei = dev_priv->rps.down_ei;
+}
 
+static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
+{
+       struct intel_rps_ei now;
+       u32 events = 0;
 
-       /*
-        * To down throttle, C0 residency should be less than down threshold
-        * for continous EI intervals. So calculate down EI counters
-        * once in VLV_INT_COUNT_FOR_DOWN_EI
-        */
-       if (dev_priv->rps.ei_interrupt_count == VLV_INT_COUNT_FOR_DOWN_EI) {
+       if ((pm_iir & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED)) == 0)
+               return 0;
 
-               dev_priv->rps.ei_interrupt_count = 0;
+       vlv_c0_read(dev_priv, &now);
+       if (now.cz_clock == 0)
+               return 0;
 
-               residency_C0_down = vlv_c0_residency(dev_priv,
-                                                    &dev_priv->rps.down_ei);
-       } else {
-               residency_C0_up = vlv_c0_residency(dev_priv,
-                                                  &dev_priv->rps.up_ei);
+       if (pm_iir & GEN6_PM_RP_DOWN_EI_EXPIRED) {
+               if (!vlv_c0_above(dev_priv,
+                                 &dev_priv->rps.down_ei, &now,
+                                 VLV_RP_DOWN_EI_THRESHOLD))
+                       events |= GEN6_PM_RP_DOWN_THRESHOLD;
+               dev_priv->rps.down_ei = now;
        }
 
-       new_delay = dev_priv->rps.cur_freq;
-
-       adj = dev_priv->rps.last_adj;
-       /* C0 residency is greater than UP threshold. Increase Frequency */
-       if (residency_C0_up >= VLV_RP_UP_EI_THRESHOLD) {
-               if (adj > 0)
-                       adj *= 2;
-               else
-                       adj = 1;
-
-               if (dev_priv->rps.cur_freq < dev_priv->rps.max_freq_softlimit)
-                       new_delay = dev_priv->rps.cur_freq + adj;
-
-               /*
-                * For better performance, jump directly
-                * to RPe if we're below it.
-                */
-               if (new_delay < dev_priv->rps.efficient_freq)
-                       new_delay = dev_priv->rps.efficient_freq;
-
-       } else if (!dev_priv->rps.ei_interrupt_count &&
-                       (residency_C0_down < VLV_RP_DOWN_EI_THRESHOLD)) {
-               if (adj < 0)
-                       adj *= 2;
-               else
-                       adj = -1;
-               /*
-                * This means, C0 residency is less than down threshold over
-                * a period of VLV_INT_COUNT_FOR_DOWN_EI. So, reduce the freq
-                */
-               if (dev_priv->rps.cur_freq > dev_priv->rps.min_freq_softlimit)
-                       new_delay = dev_priv->rps.cur_freq + adj;
+       if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) {
+               if (vlv_c0_above(dev_priv,
+                                &dev_priv->rps.up_ei, &now,
+                                VLV_RP_UP_EI_THRESHOLD))
+                       events |= GEN6_PM_RP_UP_THRESHOLD;
+               dev_priv->rps.up_ei = now;
        }
 
-       return new_delay;
+       return events;
 }
 
 static void gen6_pm_rps_work(struct work_struct *work)
@@ -1149,6 +1092,8 @@ static void gen6_pm_rps_work(struct work_struct *work)
 
        mutex_lock(&dev_priv->rps.hw_lock);
 
+       pm_iir |= vlv_wa_c0_ei(dev_priv, pm_iir);
+
        adj = dev_priv->rps.last_adj;
        if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
                if (adj > 0)
@@ -1171,8 +1116,6 @@ static void gen6_pm_rps_work(struct work_struct *work)
                else
                        new_delay = dev_priv->rps.min_freq_softlimit;
                adj = 0;
-       } else if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) {
-               new_delay = vlv_calc_delay_from_C0_counters(dev_priv);
        } else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
                if (adj < 0)
                        adj *= 2;
@@ -4299,7 +4242,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
        /* Let's track the enabled rps events */
        if (IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
                /* WaGsvRC0ResidencyMethod:vlv */
-               dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
+               dev_priv->pm_rps_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED;
        else
                dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
 
index e2d20ff..bb64415 100644 (file)
@@ -27,7 +27,6 @@
 struct i915_params i915 __read_mostly = {
        .modeset = -1,
        .panel_ignore_lid = 1,
-       .powersave = 1,
        .semaphores = -1,
        .lvds_downclock = 0,
        .lvds_channel_mode = 0,
@@ -44,6 +43,7 @@ struct i915_params i915 __read_mostly = {
        .enable_ips = 1,
        .fastboot = 0,
        .prefault_disable = 0,
+       .load_detect_test = 0,
        .reset = true,
        .invert_brightness = 0,
        .disable_display = 0,
@@ -65,10 +65,6 @@ MODULE_PARM_DESC(panel_ignore_lid,
        "Override lid status (0=autodetect, 1=autodetect disabled [default], "
        "-1=force lid closed, -2=force lid open)");
 
-module_param_named(powersave, i915.powersave, int, 0600);
-MODULE_PARM_DESC(powersave,
-       "Enable powersavings, fbc, downclocking, etc. (default: true)");
-
 module_param_named_unsafe(semaphores, i915.semaphores, int, 0400);
 MODULE_PARM_DESC(semaphores,
        "Use semaphores for inter-ring sync "
@@ -144,11 +140,16 @@ module_param_named(fastboot, i915.fastboot, bool, 0600);
 MODULE_PARM_DESC(fastboot,
        "Try to skip unnecessary mode sets at boot time (default: false)");
 
-module_param_named(prefault_disable, i915.prefault_disable, bool, 0600);
+module_param_named_unsafe(prefault_disable, i915.prefault_disable, bool, 0600);
 MODULE_PARM_DESC(prefault_disable,
        "Disable page prefaulting for pread/pwrite/reloc (default:false). "
        "For developers only.");
 
+module_param_named_unsafe(load_detect_test, i915.load_detect_test, bool, 0600);
+MODULE_PARM_DESC(load_detect_test,
+       "Force-enable the VGA load detect code for testing (default:false). "
+       "For developers only.");
+
 module_param_named(invert_brightness, i915.invert_brightness, int, 0600);
 MODULE_PARM_DESC(invert_brightness,
        "Invert backlight brightness "
index cc8ebab..b522eb6 100644 (file)
@@ -673,7 +673,6 @@ enum skl_disp_power_wells {
 #define VLV_CZ_CLOCK_TO_MILLI_SEC              100000
 #define VLV_RP_UP_EI_THRESHOLD                 90
 #define VLV_RP_DOWN_EI_THRESHOLD               70
-#define VLV_INT_COUNT_FOR_DOWN_EI              5
 
 /* vlv2 north clock has */
 #define CCK_FUSE_REG                           0x8
@@ -1307,6 +1306,9 @@ enum skl_disp_power_wells {
 #define   ERR_INT_FIFO_UNDERRUN_A      (1<<0)
 #define   ERR_INT_FIFO_UNDERRUN(pipe)  (1<<(pipe*3))
 
+#define GEN8_FAULT_TLB_DATA0           0x04b10
+#define GEN8_FAULT_TLB_DATA1           0x04b14
+
 #define FPGA_DBG               0x42300
 #define   FPGA_DBG_RM_NOCLAIM  (1<<31)
 
@@ -6220,8 +6222,8 @@ enum skl_disp_power_wells {
 
 #define GEN6_GT_GFX_RC6p                       0x13810C
 #define GEN6_GT_GFX_RC6pp                      0x138110
-#define VLV_RENDER_C0_COUNT_REG                0x138118
-#define VLV_MEDIA_C0_COUNT_REG                 0x13811C
+#define VLV_RENDER_C0_COUNT                    0x138118
+#define VLV_MEDIA_C0_COUNT                     0x13811C
 
 #define GEN6_PCODE_MAILBOX                     0x138124
 #define   GEN6_PCODE_READY                     (1<<31)
index f004d3d..b3070a4 100644 (file)
@@ -156,6 +156,105 @@ TRACE_EVENT(i915_vma_unbind,
                      __entry->obj, __entry->offset, __entry->size, __entry->vm)
 );
 
+#define VM_TO_TRACE_NAME(vm) \
+       (i915_is_ggtt(vm) ? "G" : \
+                     "P")
+
+DECLARE_EVENT_CLASS(i915_va,
+       TP_PROTO(struct i915_address_space *vm, u64 start, u64 length, const char *name),
+       TP_ARGS(vm, start, length, name),
+
+       TP_STRUCT__entry(
+               __field(struct i915_address_space *, vm)
+               __field(u64, start)
+               __field(u64, end)
+               __string(name, name)
+       ),
+
+       TP_fast_assign(
+               __entry->vm = vm;
+               __entry->start = start;
+               __entry->end = start + length - 1;
+               __assign_str(name, name);
+       ),
+
+       TP_printk("vm=%p (%s), 0x%llx-0x%llx",
+                 __entry->vm, __get_str(name),  __entry->start, __entry->end)
+);
+
+DEFINE_EVENT(i915_va, i915_va_alloc,
+            TP_PROTO(struct i915_address_space *vm, u64 start, u64 length, const char *name),
+            TP_ARGS(vm, start, length, name)
+);
+
+DECLARE_EVENT_CLASS(i915_page_table_entry,
+       TP_PROTO(struct i915_address_space *vm, u32 pde, u64 start, u64 pde_shift),
+       TP_ARGS(vm, pde, start, pde_shift),
+
+       TP_STRUCT__entry(
+               __field(struct i915_address_space *, vm)
+               __field(u32, pde)
+               __field(u64, start)
+               __field(u64, end)
+       ),
+
+       TP_fast_assign(
+               __entry->vm = vm;
+               __entry->pde = pde;
+               __entry->start = start;
+               __entry->end = ((start + (1ULL << pde_shift)) & ~((1ULL << pde_shift)-1)) - 1;
+       ),
+
+       TP_printk("vm=%p, pde=%d (0x%llx-0x%llx)",
+                 __entry->vm, __entry->pde, __entry->start, __entry->end)
+);
+
+DEFINE_EVENT(i915_page_table_entry, i915_page_table_entry_alloc,
+            TP_PROTO(struct i915_address_space *vm, u32 pde, u64 start, u64 pde_shift),
+            TP_ARGS(vm, pde, start, pde_shift)
+);
+
+/* Avoid extra math because we only support two sizes. The format is defined by
+ * bitmap_scnprintf. Each 32 bits is 8 HEX digits followed by comma */
+#define TRACE_PT_SIZE(bits) \
+       ((((bits) == 1024) ? 288 : 144) + 1)
+
+DECLARE_EVENT_CLASS(i915_page_table_entry_update,
+       TP_PROTO(struct i915_address_space *vm, u32 pde,
+                struct i915_page_table_entry *pt, u32 first, u32 count, u32 bits),
+       TP_ARGS(vm, pde, pt, first, count, bits),
+
+       TP_STRUCT__entry(
+               __field(struct i915_address_space *, vm)
+               __field(u32, pde)
+               __field(u32, first)
+               __field(u32, last)
+               __dynamic_array(char, cur_ptes, TRACE_PT_SIZE(bits))
+       ),
+
+       TP_fast_assign(
+               __entry->vm = vm;
+               __entry->pde = pde;
+               __entry->first = first;
+               __entry->last = first + count - 1;
+               scnprintf(__get_str(cur_ptes),
+                         TRACE_PT_SIZE(bits),
+                         "%*pb",
+                         bits,
+                         pt->used_ptes);
+       ),
+
+       TP_printk("vm=%p, pde=%d, updating %u:%u\t%s",
+                 __entry->vm, __entry->pde, __entry->last, __entry->first,
+                 __get_str(cur_ptes))
+);
+
+DEFINE_EVENT(i915_page_table_entry_update, i915_page_table_entry_map,
+       TP_PROTO(struct i915_address_space *vm, u32 pde,
+                struct i915_page_table_entry *pt, u32 first, u32 count, u32 bits),
+       TP_ARGS(vm, pde, pt, first, count, bits)
+);
+
 TRACE_EVENT(i915_gem_object_change_domain,
            TP_PROTO(struct drm_i915_gem_object *obj, u32 old_read, u32 old_write),
            TP_ARGS(obj, old_read, old_write),
index e66e17a..6095a99 100644 (file)
@@ -690,7 +690,7 @@ intel_crt_detect(struct drm_connector *connector, bool force)
         * broken monitor (without edid) to work behind a broken kvm (that fails
         * to have the right resistors for HP detection) needs to fix this up.
         * For now just bail out. */
-       if (I915_HAS_HOTPLUG(dev)) {
+       if (I915_HAS_HOTPLUG(dev) && !i915.load_detect_test) {
                status = connector_status_disconnected;
                goto out;
        }
@@ -706,9 +706,11 @@ intel_crt_detect(struct drm_connector *connector, bool force)
        if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) {
                if (intel_crt_detect_ddc(connector))
                        status = connector_status_connected;
-               else
+               else if (INTEL_INFO(dev)->gen < 4)
                        status = intel_crt_load_detect(crt);
-               intel_release_load_detect_pipe(connector, &tmp);
+               else
+                       status = connector_status_unknown;
+               intel_release_load_detect_pipe(connector, &tmp, &ctx);
        } else
                status = connector_status_unknown;
 
@@ -794,6 +796,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
        .destroy = intel_crt_destroy,
        .set_property = intel_crt_set_property,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
        .atomic_get_property = intel_connector_atomic_get_property,
 };
 
index 8aee7d7..47b9307 100644 (file)
@@ -492,17 +492,23 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc)
 }
 
 static struct intel_encoder *
-intel_ddi_get_crtc_new_encoder(struct intel_crtc *crtc)
+intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct intel_encoder *intel_encoder, *ret = NULL;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct intel_encoder *ret = NULL;
+       struct drm_atomic_state *state;
        int num_encoders = 0;
+       int i;
 
-       for_each_intel_encoder(dev, intel_encoder) {
-               if (intel_encoder->new_crtc == crtc) {
-                       ret = intel_encoder;
-                       num_encoders++;
-               }
+       state = crtc_state->base.state;
+
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i] ||
+                   state->connector_states[i]->crtc != crtc_state->base.crtc)
+                       continue;
+
+               ret = to_intel_encoder(state->connector_states[i]->best_encoder);
+               num_encoders++;
        }
 
        WARN(num_encoders != 1, "%d encoders on crtc for pipe %c\n", num_encoders,
@@ -1216,7 +1222,7 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc,
 {
        struct drm_device *dev = intel_crtc->base.dev;
        struct intel_encoder *intel_encoder =
-               intel_ddi_get_crtc_new_encoder(intel_crtc);
+               intel_ddi_get_crtc_new_encoder(crtc_state);
        int clock = crtc_state->port_clock;
 
        if (IS_SKYLAKE(dev))
index 90b460c..75955fe 100644 (file)
@@ -83,7 +83,8 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc,
                                   struct intel_crtc_state *pipe_config);
 
 static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
-                         int x, int y, struct drm_framebuffer *old_fb);
+                         int x, int y, struct drm_framebuffer *old_fb,
+                         struct drm_atomic_state *state);
 static int intel_framebuffer_init(struct drm_device *dev,
                                  struct intel_framebuffer *ifb,
                                  struct drm_mode_fb_cmd2 *mode_cmd,
@@ -430,25 +431,41 @@ bool intel_pipe_has_type(struct intel_crtc *crtc, enum intel_output_type type)
  * intel_pipe_has_type() but looking at encoder->new_crtc instead of
  * encoder->crtc.
  */
-static bool intel_pipe_will_have_type(struct intel_crtc *crtc, int type)
+static bool intel_pipe_will_have_type(const struct intel_crtc_state *crtc_state,
+                                     int type)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_atomic_state *state = crtc_state->base.state;
+       struct drm_connector_state *connector_state;
        struct intel_encoder *encoder;
+       int i, num_connectors = 0;
+
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
+                       continue;
+
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != crtc_state->base.crtc)
+                       continue;
 
-       for_each_intel_encoder(dev, encoder)
-               if (encoder->new_crtc == crtc && encoder->type == type)
+               num_connectors++;
+
+               encoder = to_intel_encoder(connector_state->best_encoder);
+               if (encoder->type == type)
                        return true;
+       }
+
+       WARN_ON(num_connectors == 0);
 
        return false;
 }
 
-static const intel_limit_t *intel_ironlake_limit(struct intel_crtc *crtc,
-                                               int refclk)
+static const intel_limit_t *
+intel_ironlake_limit(struct intel_crtc_state *crtc_state, int refclk)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
        const intel_limit_t *limit;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                if (intel_is_dual_link_lvds(dev)) {
                        if (refclk == 100000)
                                limit = &intel_limits_ironlake_dual_lvds_100m;
@@ -466,20 +483,21 @@ static const intel_limit_t *intel_ironlake_limit(struct intel_crtc *crtc,
        return limit;
 }
 
-static const intel_limit_t *intel_g4x_limit(struct intel_crtc *crtc)
+static const intel_limit_t *
+intel_g4x_limit(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
        const intel_limit_t *limit;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                if (intel_is_dual_link_lvds(dev))
                        limit = &intel_limits_g4x_dual_channel_lvds;
                else
                        limit = &intel_limits_g4x_single_channel_lvds;
-       } else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_HDMI) ||
-                  intel_pipe_will_have_type(crtc, INTEL_OUTPUT_ANALOG)) {
+       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_HDMI) ||
+                  intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
                limit = &intel_limits_g4x_hdmi;
-       } else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_SDVO)) {
+       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_SDVO)) {
                limit = &intel_limits_g4x_sdvo;
        } else /* The option is for other outputs */
                limit = &intel_limits_i9xx_sdvo;
@@ -487,17 +505,18 @@ static const intel_limit_t *intel_g4x_limit(struct intel_crtc *crtc)
        return limit;
 }
 
-static const intel_limit_t *intel_limit(struct intel_crtc *crtc, int refclk)
+static const intel_limit_t *
+intel_limit(struct intel_crtc_state *crtc_state, int refclk)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
        const intel_limit_t *limit;
 
        if (HAS_PCH_SPLIT(dev))
-               limit = intel_ironlake_limit(crtc, refclk);
+               limit = intel_ironlake_limit(crtc_state, refclk);
        else if (IS_G4X(dev)) {
-               limit = intel_g4x_limit(crtc);
+               limit = intel_g4x_limit(crtc_state);
        } else if (IS_PINEVIEW(dev)) {
-               if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS))
+               if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_pineview_lvds;
                else
                        limit = &intel_limits_pineview_sdvo;
@@ -506,14 +525,14 @@ static const intel_limit_t *intel_limit(struct intel_crtc *crtc, int refclk)
        } else if (IS_VALLEYVIEW(dev)) {
                limit = &intel_limits_vlv;
        } else if (!IS_GEN2(dev)) {
-               if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS))
+               if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_i9xx_lvds;
                else
                        limit = &intel_limits_i9xx_sdvo;
        } else {
-               if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS))
+               if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_i8xx_lvds;
-               else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_DVO))
+               else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_DVO))
                        limit = &intel_limits_i8xx_dvo;
                else
                        limit = &intel_limits_i8xx_dac;
@@ -600,15 +619,17 @@ static bool intel_PLL_is_valid(struct drm_device *dev,
 }
 
 static bool
-i9xx_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
+i9xx_find_best_dpll(const intel_limit_t *limit,
+                   struct intel_crtc_state *crtc_state,
                    int target, int refclk, intel_clock_t *match_clock,
                    intel_clock_t *best_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        intel_clock_t clock;
        int err = target;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                /*
                 * For LVDS just rely on its current settings for dual-channel.
                 * We haven't figured out how to reliably set up different
@@ -661,15 +682,17 @@ i9xx_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
 }
 
 static bool
-pnv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
+pnv_find_best_dpll(const intel_limit_t *limit,
+                  struct intel_crtc_state *crtc_state,
                   int target, int refclk, intel_clock_t *match_clock,
                   intel_clock_t *best_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        intel_clock_t clock;
        int err = target;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                /*
                 * For LVDS just rely on its current settings for dual-channel.
                 * We haven't figured out how to reliably set up different
@@ -720,10 +743,12 @@ pnv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
 }
 
 static bool
-g4x_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
+g4x_find_best_dpll(const intel_limit_t *limit,
+                  struct intel_crtc_state *crtc_state,
                   int target, int refclk, intel_clock_t *match_clock,
                   intel_clock_t *best_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        intel_clock_t clock;
        int max_n;
@@ -732,7 +757,7 @@ g4x_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
        int err_most = (target >> 8) + (target >> 9);
        found = false;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                if (intel_is_dual_link_lvds(dev))
                        clock.p2 = limit->p2.p2_fast;
                else
@@ -776,11 +801,53 @@ g4x_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
        return found;
 }
 
+/*
+ * Check if the calculated PLL configuration is more optimal compared to the
+ * best configuration and error found so far. Return the calculated error.
+ */
+static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
+                              const intel_clock_t *calculated_clock,
+                              const intel_clock_t *best_clock,
+                              unsigned int best_error_ppm,
+                              unsigned int *error_ppm)
+{
+       /*
+        * For CHV ignore the error and consider only the P value.
+        * Prefer a bigger P value based on HW requirements.
+        */
+       if (IS_CHERRYVIEW(dev)) {
+               *error_ppm = 0;
+
+               return calculated_clock->p > best_clock->p;
+       }
+
+       if (WARN_ON_ONCE(!target_freq))
+               return false;
+
+       *error_ppm = div_u64(1000000ULL *
+                               abs(target_freq - calculated_clock->dot),
+                            target_freq);
+       /*
+        * Prefer a better P value over a better (smaller) error if the error
+        * is small. Ensure this preference for future configurations too by
+        * setting the error to 0.
+        */
+       if (*error_ppm < 100 && calculated_clock->p > best_clock->p) {
+               *error_ppm = 0;
+
+               return true;
+       }
+
+       return *error_ppm + 10 < best_error_ppm;
+}
+
 static bool
-vlv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
+vlv_find_best_dpll(const intel_limit_t *limit,
+                  struct intel_crtc_state *crtc_state,
                   int target, int refclk, intel_clock_t *match_clock,
                   intel_clock_t *best_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        intel_clock_t clock;
        unsigned int bestppm = 1000000;
@@ -800,7 +867,7 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
                                clock.p = clock.p1 * clock.p2;
                                /* based on hardware requirement, prefer bigger m1,m2 values */
                                for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
-                                       unsigned int ppm, diff;
+                                       unsigned int ppm;
 
                                        clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n,
                                                                     refclk * clock.m1);
@@ -811,20 +878,15 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
                                                                &clock))
                                                continue;
 
-                                       diff = abs(clock.dot - target);
-                                       ppm = div_u64(1000000ULL * diff, target);
-
-                                       if (ppm < 100 && clock.p > best_clock->p) {
-                                               bestppm = 0;
-                                               *best_clock = clock;
-                                               found = true;
-                                       }
+                                       if (!vlv_PLL_is_optimal(dev, target,
+                                                               &clock,
+                                                               best_clock,
+                                                               bestppm, &ppm))
+                                               continue;
 
-                                       if (bestppm >= 10 && ppm < bestppm - 10) {
-                                               bestppm = ppm;
-                                               *best_clock = clock;
-                                               found = true;
-                                       }
+                                       *best_clock = clock;
+                                       bestppm = ppm;
+                                       found = true;
                                }
                        }
                }
@@ -834,16 +896,20 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
 }
 
 static bool
-chv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
+chv_find_best_dpll(const intel_limit_t *limit,
+                  struct intel_crtc_state *crtc_state,
                   int target, int refclk, intel_clock_t *match_clock,
                   intel_clock_t *best_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
+       unsigned int best_error_ppm;
        intel_clock_t clock;
        uint64_t m2;
        int found = false;
 
        memset(best_clock, 0, sizeof(*best_clock));
+       best_error_ppm = 1000000;
 
        /*
         * Based on hardware doc, the n always set to 1, and m1 always
@@ -857,6 +923,7 @@ chv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
                for (clock.p2 = limit->p2.p2_fast;
                                clock.p2 >= limit->p2.p2_slow;
                                clock.p2 -= clock.p2 > 10 ? 2 : 1) {
+                       unsigned int error_ppm;
 
                        clock.p = clock.p1 * clock.p2;
 
@@ -873,12 +940,13 @@ chv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
                        if (!intel_PLL_is_valid(dev, limit, &clock))
                                continue;
 
-                       /* based on hardware requirement, prefer bigger p
-                        */
-                       if (clock.p > best_clock->p) {
-                               *best_clock = clock;
-                               found = true;
-                       }
+                       if (!vlv_PLL_is_optimal(dev, target, &clock, best_clock,
+                                               best_error_ppm, &error_ppm))
+                               continue;
+
+                       *best_clock = clock;
+                       best_error_ppm = error_ppm;
+                       found = true;
                }
        }
 
@@ -2194,13 +2262,12 @@ static bool need_vtd_wa(struct drm_device *dev)
        return false;
 }
 
-int
-intel_fb_align_height(struct drm_device *dev, int height,
-                     uint32_t pixel_format,
-                     uint64_t fb_format_modifier)
+unsigned int
+intel_tile_height(struct drm_device *dev, uint32_t pixel_format,
+                 uint64_t fb_format_modifier)
 {
-       int tile_height;
-       uint32_t bits_per_pixel;
+       unsigned int tile_height;
+       uint32_t pixel_bytes;
 
        switch (fb_format_modifier) {
        case DRM_FORMAT_MOD_NONE:
@@ -2213,20 +2280,20 @@ intel_fb_align_height(struct drm_device *dev, int height,
                tile_height = 32;
                break;
        case I915_FORMAT_MOD_Yf_TILED:
-               bits_per_pixel = drm_format_plane_cpp(pixel_format, 0) * 8;
-               switch (bits_per_pixel) {
+               pixel_bytes = drm_format_plane_cpp(pixel_format, 0);
+               switch (pixel_bytes) {
                default:
-               case 8:
+               case 1:
                        tile_height = 64;
                        break;
-               case 16:
-               case 32:
+               case 2:
+               case 4:
                        tile_height = 32;
                        break;
-               case 64:
+               case 8:
                        tile_height = 16;
                        break;
-               case 128:
+               case 16:
                        WARN_ONCE(1,
                                  "128-bit pixels are not supported for display!");
                        tile_height = 16;
@@ -2239,17 +2306,58 @@ intel_fb_align_height(struct drm_device *dev, int height,
                break;
        }
 
-       return ALIGN(height, tile_height);
+       return tile_height;
+}
+
+unsigned int
+intel_fb_align_height(struct drm_device *dev, unsigned int height,
+                     uint32_t pixel_format, uint64_t fb_format_modifier)
+{
+       return ALIGN(height, intel_tile_height(dev, pixel_format,
+                                              fb_format_modifier));
+}
+
+static int
+intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
+                       const struct drm_plane_state *plane_state)
+{
+       struct intel_rotation_info *info = &view->rotation_info;
+
+       *view = i915_ggtt_view_normal;
+
+       if (!plane_state)
+               return 0;
+
+       if (!intel_rotation_90_or_270(plane_state->rotation))
+               return 0;
+
+       *view = i915_ggtt_view_rotated;
+
+       info->height = fb->height;
+       info->pixel_format = fb->pixel_format;
+       info->pitch = fb->pitches[0];
+       info->fb_modifier = fb->modifier[0];
+
+       if (!(info->fb_modifier == I915_FORMAT_MOD_Y_TILED ||
+             info->fb_modifier == I915_FORMAT_MOD_Yf_TILED)) {
+               DRM_DEBUG_KMS(
+                             "Y or Yf tiling is needed for 90/270 rotation!\n");
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
 int
 intel_pin_and_fence_fb_obj(struct drm_plane *plane,
                           struct drm_framebuffer *fb,
+                          const struct drm_plane_state *plane_state,
                           struct intel_engine_cs *pipelined)
 {
        struct drm_device *dev = fb->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       struct i915_ggtt_view view;
        u32 alignment;
        int ret;
 
@@ -2286,6 +2394,10 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
                return -EINVAL;
        }
 
+       ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
+       if (ret)
+               return ret;
+
        /* Note that the w/a also requires 64 PTE of padding following the
         * bo. We currently fill all unused PTE with the shadow page and so
         * we should always have valid PTE following the scanout preventing
@@ -2304,7 +2416,8 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
        intel_runtime_pm_get(dev_priv);
 
        dev_priv->mm.interruptible = false;
-       ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined);
+       ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined,
+                                                  &view);
        if (ret)
                goto err_interruptible;
 
@@ -2324,19 +2437,27 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
        return 0;
 
 err_unpin:
-       i915_gem_object_unpin_from_display_plane(obj);
+       i915_gem_object_unpin_from_display_plane(obj, &view);
 err_interruptible:
        dev_priv->mm.interruptible = true;
        intel_runtime_pm_put(dev_priv);
        return ret;
 }
 
-static void intel_unpin_fb_obj(struct drm_i915_gem_object *obj)
+static void intel_unpin_fb_obj(struct drm_framebuffer *fb,
+                              const struct drm_plane_state *plane_state)
 {
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       struct i915_ggtt_view view;
+       int ret;
+
        WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex));
 
+       ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
+       WARN_ONCE(ret, "Couldn't get view from plane state!");
+
        i915_gem_object_unpin_fence(obj);
-       i915_gem_object_unpin_from_display_plane(obj);
+       i915_gem_object_unpin_from_display_plane(obj, &view);
 }
 
 /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel
@@ -2414,8 +2535,8 @@ static int skl_format_to_fourcc(int format, bool rgb_order, bool alpha)
 }
 
 static bool
-intel_alloc_plane_obj(struct intel_crtc *crtc,
-                     struct intel_initial_plane_config *plane_config)
+intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
+                             struct intel_initial_plane_config *plane_config)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_gem_object *obj = NULL;
@@ -2449,17 +2570,14 @@ intel_alloc_plane_obj(struct intel_crtc *crtc,
        mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
 
        mutex_lock(&dev->struct_mutex);
-
        if (intel_framebuffer_init(dev, to_intel_framebuffer(fb),
                                   &mode_cmd, obj)) {
                DRM_DEBUG_KMS("intel fb init failed\n");
                goto out_unref_obj;
        }
-
-       obj->frontbuffer_bits = INTEL_FRONTBUFFER_PRIMARY(crtc->pipe);
        mutex_unlock(&dev->struct_mutex);
 
-       DRM_DEBUG_KMS("plane fb obj %p\n", obj);
+       DRM_DEBUG_KMS("initial plane fb obj %p\n", obj);
        return true;
 
 out_unref_obj:
@@ -2483,26 +2601,23 @@ update_state_fb(struct drm_plane *plane)
 }
 
 static void
-intel_find_plane_obj(struct intel_crtc *intel_crtc,
-                    struct intel_initial_plane_config *plane_config)
+intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
+                            struct intel_initial_plane_config *plane_config)
 {
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *c;
        struct intel_crtc *i;
        struct drm_i915_gem_object *obj;
+       struct drm_plane *primary = intel_crtc->base.primary;
+       struct drm_framebuffer *fb;
 
        if (!plane_config->fb)
                return;
 
-       if (intel_alloc_plane_obj(intel_crtc, plane_config)) {
-               struct drm_plane *primary = intel_crtc->base.primary;
-
-               primary->fb = &plane_config->fb->base;
-               primary->state->crtc = &intel_crtc->base;
-               update_state_fb(primary);
-
-               return;
+       if (intel_alloc_initial_plane_obj(intel_crtc, plane_config)) {
+               fb = &plane_config->fb->base;
+               goto valid_fb;
        }
 
        kfree(plane_config->fb);
@@ -2520,24 +2635,29 @@ intel_find_plane_obj(struct intel_crtc *intel_crtc,
                if (!i->active)
                        continue;
 
-               obj = intel_fb_obj(c->primary->fb);
-               if (obj == NULL)
+               fb = c->primary->fb;
+               if (!fb)
                        continue;
 
+               obj = intel_fb_obj(fb);
                if (i915_gem_obj_ggtt_offset(obj) == plane_config->base) {
-                       struct drm_plane *primary = intel_crtc->base.primary;
-
-                       if (obj->tiling_mode != I915_TILING_NONE)
-                               dev_priv->preserve_bios_swizzle = true;
-
-                       drm_framebuffer_reference(c->primary->fb);
-                       primary->fb = c->primary->fb;
-                       primary->state->crtc = &intel_crtc->base;
-                       update_state_fb(intel_crtc->base.primary);
-                       obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
-                       break;
+                       drm_framebuffer_reference(fb);
+                       goto valid_fb;
                }
        }
+
+       return;
+
+valid_fb:
+       obj = intel_fb_obj(fb);
+       if (obj->tiling_mode != I915_TILING_NONE)
+               dev_priv->preserve_bios_swizzle = true;
+
+       primary->fb = fb;
+       primary->state->crtc = &intel_crtc->base;
+       primary->crtc = &intel_crtc->base;
+       update_state_fb(primary);
+       obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
 }
 
 static void i9xx_update_primary_plane(struct drm_crtc *crtc,
@@ -2805,6 +2925,17 @@ u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier,
        }
 }
 
+unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
+                                    struct drm_i915_gem_object *obj)
+{
+       const struct i915_ggtt_view *view = &i915_ggtt_view_normal;
+
+       if (intel_rotation_90_or_270(intel_plane->base.state->rotation))
+               view = &i915_ggtt_view_rotated;
+
+       return i915_gem_obj_ggtt_offset_view(obj, view);
+}
+
 static void skylake_update_primary_plane(struct drm_crtc *crtc,
                                         struct drm_framebuffer *fb,
                                         int x, int y)
@@ -2815,6 +2946,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
        struct drm_i915_gem_object *obj;
        int pipe = intel_crtc->pipe;
        u32 plane_ctl, stride_div;
+       unsigned long surf_addr;
 
        if (!intel_crtc->primary_enabled) {
                I915_WRITE(PLANE_CTL(pipe, 0), 0);
@@ -2881,16 +3013,16 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
        obj = intel_fb_obj(fb);
        stride_div = intel_fb_stride_alignment(dev, fb->modifier[0],
                                               fb->pixel_format);
+       surf_addr = intel_plane_obj_offset(to_intel_plane(crtc->primary), obj);
 
        I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
-
        I915_WRITE(PLANE_POS(pipe, 0), 0);
        I915_WRITE(PLANE_OFFSET(pipe, 0), (y << 16) | x);
        I915_WRITE(PLANE_SIZE(pipe, 0),
                   (intel_crtc->config->pipe_src_h - 1) << 16 |
                   (intel_crtc->config->pipe_src_w - 1));
        I915_WRITE(PLANE_STRIDE(pipe, 0), fb->pitches[0] / stride_div);
-       I915_WRITE(PLANE_SURF(pipe, 0), i915_gem_obj_ggtt_offset(obj));
+       I915_WRITE(PLANE_SURF(pipe, 0), surf_addr);
 
        POSTING_READ(PLANE_SURF(pipe, 0));
 }
@@ -4824,8 +4956,9 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
        return mask;
 }
 
-static void modeset_update_crtc_power_domains(struct drm_device *dev)
+static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
 {
+       struct drm_device *dev = state->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long pipe_domains[I915_MAX_PIPES] = { 0, };
        struct intel_crtc *crtc;
@@ -4847,7 +4980,7 @@ static void modeset_update_crtc_power_domains(struct drm_device *dev)
        }
 
        if (dev_priv->display.modeset_global_resources)
-               dev_priv->display.modeset_global_resources(dev);
+               dev_priv->display.modeset_global_resources(state);
 
        for_each_intel_crtc(dev, crtc) {
                enum intel_display_power_domain domain;
@@ -5095,8 +5228,9 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
        WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND);
 }
 
-static void valleyview_modeset_global_resources(struct drm_device *dev)
+static void valleyview_modeset_global_resources(struct drm_atomic_state *state)
 {
+       struct drm_device *dev = state->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int max_pixclk = intel_mode_max_pixclk(dev_priv);
        int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
@@ -5687,7 +5821,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
         * - LVDS dual channel mode
         * - Double wide pipe
         */
-       if ((intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
+       if ((intel_pipe_will_have_type(pipe_config, INTEL_OUTPUT_LVDS) &&
             intel_is_dual_link_lvds(dev)) || pipe_config->double_wide)
                pipe_config->pipe_src_w &= ~1;
 
@@ -5866,15 +6000,18 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
                && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
 }
 
-static int i9xx_get_refclk(struct intel_crtc *crtc, int num_connectors)
+static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
+                          int num_connectors)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int refclk;
 
+       WARN_ON(!crtc_state->base.state);
+
        if (IS_VALLEYVIEW(dev)) {
                refclk = 100000;
-       } else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
+       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
            intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
                refclk = dev_priv->vbt.lvds_ssc_freq;
                DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
@@ -5917,8 +6054,8 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
        crtc_state->dpll_hw_state.fp0 = fp;
 
        crtc->lowfreq_avail = false;
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
-           reduced_clock && i915.powersave) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
+           reduced_clock) {
                crtc_state->dpll_hw_state.fp1 = fp2;
                crtc->lowfreq_avail = true;
        } else {
@@ -6275,6 +6412,7 @@ void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
        struct intel_crtc *crtc =
                to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
        struct intel_crtc_state pipe_config = {
+               .base.crtc = &crtc->base,
                .pixel_multiplier = 1,
                .dpll = *dpll,
        };
@@ -6319,12 +6457,12 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
 
        i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
 
-       is_sdvo = intel_pipe_will_have_type(crtc, INTEL_OUTPUT_SDVO) ||
-               intel_pipe_will_have_type(crtc, INTEL_OUTPUT_HDMI);
+       is_sdvo = intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_SDVO) ||
+               intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_HDMI);
 
        dpll = DPLL_VGA_MODE_DIS;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS))
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
                dpll |= DPLLB_MODE_LVDS;
        else
                dpll |= DPLLB_MODE_DAC_SERIAL;
@@ -6367,7 +6505,7 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
 
        if (crtc_state->sdvo_tv_clock)
                dpll |= PLL_REF_INPUT_TVCLKINBC;
-       else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
+       else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
                 intel_panel_use_ssc(dev_priv) && num_connectors < 2)
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
@@ -6397,7 +6535,7 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
 
        dpll = DPLL_VGA_MODE_DIS;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
        } else {
                if (clock->p1 == 2)
@@ -6408,10 +6546,10 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
                        dpll |= PLL_P2_DIVIDE_BY_4;
        }
 
-       if (!IS_I830(dev) && intel_pipe_will_have_type(crtc, INTEL_OUTPUT_DVO))
+       if (!IS_I830(dev) && intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_DVO))
                dpll |= DPLL_DVO_2X_MODE;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
                 intel_panel_use_ssc(dev_priv) && num_connectors < 2)
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
@@ -6625,11 +6763,20 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
        bool is_lvds = false, is_dsi = false;
        struct intel_encoder *encoder;
        const intel_limit_t *limit;
+       struct drm_atomic_state *state = crtc_state->base.state;
+       struct drm_connector_state *connector_state;
+       int i;
 
-       for_each_intel_encoder(dev, encoder) {
-               if (encoder->new_crtc != crtc)
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
                        continue;
 
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != &crtc->base)
+                       continue;
+
+               encoder = to_intel_encoder(connector_state->best_encoder);
+
                switch (encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
@@ -6648,7 +6795,7 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
                return 0;
 
        if (!crtc_state->clock_set) {
-               refclk = i9xx_get_refclk(crtc, num_connectors);
+               refclk = i9xx_get_refclk(crtc_state, num_connectors);
 
                /*
                 * Returns a set of divisors for the desired target clock with
@@ -6656,8 +6803,8 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
                 * the clock equation: reflck * (5 * (m1 + 2) + (m2 + 2)) / (n +
                 * 2) / p1 / p2.
                 */
-               limit = intel_limit(crtc, refclk);
-               ok = dev_priv->display.find_dpll(limit, crtc,
+               limit = intel_limit(crtc_state, refclk);
+               ok = dev_priv->display.find_dpll(limit, crtc_state,
                                                 crtc_state->port_clock,
                                                 refclk, NULL, &clock);
                if (!ok) {
@@ -6673,7 +6820,7 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
                         * we will disable the LVDS downclock feature.
                         */
                        has_reduced_clock =
-                               dev_priv->display.find_dpll(limit, crtc,
+                               dev_priv->display.find_dpll(limit, crtc_state,
                                                            dev_priv->lvds_downclock,
                                                            refclk, &clock,
                                                            &reduced_clock);
@@ -6772,7 +6919,7 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc,
        u32 val, base, offset;
        int pipe = crtc->pipe, plane = crtc->plane;
        int fourcc, pixel_format;
-       int aligned_height;
+       unsigned int aligned_height;
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
 
@@ -7303,18 +7450,26 @@ void intel_init_pch_refclk(struct drm_device *dev)
                lpt_init_pch_refclk(dev);
 }
 
-static int ironlake_get_refclk(struct drm_crtc *crtc)
+static int ironlake_get_refclk(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_atomic_state *state = crtc_state->base.state;
+       struct drm_connector_state *connector_state;
        struct intel_encoder *encoder;
-       int num_connectors = 0;
+       int num_connectors = 0, i;
        bool is_lvds = false;
 
-       for_each_intel_encoder(dev, encoder) {
-               if (encoder->new_crtc != to_intel_crtc(crtc))
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
+                       continue;
+
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != crtc_state->base.crtc)
                        continue;
 
+               encoder = to_intel_encoder(connector_state->best_encoder);
+
                switch (encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
@@ -7501,22 +7656,21 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int refclk;
        const intel_limit_t *limit;
        bool ret, is_lvds = false;
 
-       is_lvds = intel_pipe_will_have_type(intel_crtc, INTEL_OUTPUT_LVDS);
+       is_lvds = intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS);
 
-       refclk = ironlake_get_refclk(crtc);
+       refclk = ironlake_get_refclk(crtc_state);
 
        /*
         * Returns a set of divisors for the desired target clock with the given
         * refclk, or FALSE.  The returned values represent the clock equation:
         * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
         */
-       limit = intel_limit(intel_crtc, refclk);
-       ret = dev_priv->display.find_dpll(limit, intel_crtc,
+       limit = intel_limit(crtc_state, refclk);
+       ret = dev_priv->display.find_dpll(limit, crtc_state,
                                          crtc_state->port_clock,
                                          refclk, NULL, clock);
        if (!ret)
@@ -7530,7 +7684,7 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
                 * downclock feature.
                */
                *has_reduced_clock =
-                       dev_priv->display.find_dpll(limit, intel_crtc,
+                       dev_priv->display.find_dpll(limit, crtc_state,
                                                    dev_priv->lvds_downclock,
                                                    refclk, clock,
                                                    reduced_clock);
@@ -7563,16 +7717,24 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
        struct drm_crtc *crtc = &intel_crtc->base;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *intel_encoder;
+       struct drm_atomic_state *state = crtc_state->base.state;
+       struct drm_connector_state *connector_state;
+       struct intel_encoder *encoder;
        uint32_t dpll;
-       int factor, num_connectors = 0;
+       int factor, num_connectors = 0, i;
        bool is_lvds = false, is_sdvo = false;
 
-       for_each_intel_encoder(dev, intel_encoder) {
-               if (intel_encoder->new_crtc != to_intel_crtc(crtc))
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
                        continue;
 
-               switch (intel_encoder->type) {
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != crtc_state->base.crtc)
+                       continue;
+
+               encoder = to_intel_encoder(connector_state->best_encoder);
+
+               switch (encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
                        break;
@@ -7701,7 +7863,7 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
                }
        }
 
-       if (is_lvds && has_reduced_clock && i915.powersave)
+       if (is_lvds && has_reduced_clock)
                crtc->lowfreq_avail = true;
        else
                crtc->lowfreq_avail = false;
@@ -7810,7 +7972,7 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
        u32 val, base, offset, stride_mult, tiling;
        int pipe = crtc->pipe;
        int fourcc, pixel_format;
-       int aligned_height;
+       unsigned int aligned_height;
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
 
@@ -7918,7 +8080,7 @@ ironlake_get_initial_plane_config(struct intel_crtc *crtc,
        u32 val, base, offset;
        int pipe = crtc->pipe;
        int fourcc, pixel_format;
-       int aligned_height;
+       unsigned int aligned_height;
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
 
@@ -8802,6 +8964,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        struct drm_device *dev = encoder->dev;
        struct drm_framebuffer *fb;
        struct drm_mode_config *config = &dev->mode_config;
+       struct drm_atomic_state *state = NULL;
+       struct drm_connector_state *connector_state;
        int ret, i = -1;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
@@ -8883,6 +9047,21 @@ retry:
        old->load_detect_temp = true;
        old->release_fb = NULL;
 
+       state = drm_atomic_state_alloc(dev);
+       if (!state)
+               return false;
+
+       state->acquire_ctx = ctx;
+
+       connector_state = drm_atomic_get_connector_state(state, connector);
+       if (IS_ERR(connector_state)) {
+               ret = PTR_ERR(connector_state);
+               goto fail;
+       }
+
+       connector_state->crtc = crtc;
+       connector_state->best_encoder = &intel_encoder->base;
+
        if (!mode)
                mode = &load_detect_mode;
 
@@ -8905,7 +9084,7 @@ retry:
                goto fail;
        }
 
-       if (intel_set_mode(crtc, mode, 0, 0, fb)) {
+       if (intel_set_mode(crtc, mode, 0, 0, fb, state)) {
                DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
                if (old->release_fb)
                        old->release_fb->funcs->destroy(old->release_fb);
@@ -8924,6 +9103,11 @@ retry:
        else
                intel_crtc->new_config = NULL;
 fail_unlock:
+       if (state) {
+               drm_atomic_state_free(state);
+               state = NULL;
+       }
+
        if (ret == -EDEADLK) {
                drm_modeset_backoff(ctx);
                goto retry;
@@ -8933,24 +9117,44 @@ fail_unlock:
 }
 
 void intel_release_load_detect_pipe(struct drm_connector *connector,
-                                   struct intel_load_detect_pipe *old)
+                                   struct intel_load_detect_pipe *old,
+                                   struct drm_modeset_acquire_ctx *ctx)
 {
+       struct drm_device *dev = connector->dev;
        struct intel_encoder *intel_encoder =
                intel_attached_encoder(connector);
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = encoder->crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_atomic_state *state;
+       struct drm_connector_state *connector_state;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
                      connector->base.id, connector->name,
                      encoder->base.id, encoder->name);
 
        if (old->load_detect_temp) {
+               state = drm_atomic_state_alloc(dev);
+               if (!state)
+                       goto fail;
+
+               state->acquire_ctx = ctx;
+
+               connector_state = drm_atomic_get_connector_state(state, connector);
+               if (IS_ERR(connector_state))
+                       goto fail;
+
                to_intel_connector(connector)->new_encoder = NULL;
                intel_encoder->new_crtc = NULL;
                intel_crtc->new_enabled = false;
                intel_crtc->new_config = NULL;
-               intel_set_mode(crtc, NULL, 0, 0, NULL);
+
+               connector_state->best_encoder = NULL;
+               connector_state->crtc = NULL;
+
+               intel_set_mode(crtc, NULL, 0, 0, NULL, state);
+
+               drm_atomic_state_free(state);
 
                if (old->release_fb) {
                        drm_framebuffer_unregister_private(old->release_fb);
@@ -8963,6 +9167,11 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
        /* Switch crtc and encoder back off if necessary */
        if (old->dpms_mode != DRM_MODE_DPMS_ON)
                connector->funcs->dpms(connector, old->dpms_mode);
+
+       return;
+fail:
+       DRM_DEBUG_KMS("Couldn't release load detect pipe.\n");
+       drm_atomic_state_free(state);
 }
 
 static int i9xx_pll_refclk(struct drm_device *dev,
@@ -9201,6 +9410,8 @@ void intel_mark_busy(struct drm_device *dev)
 
        intel_runtime_pm_get(dev_priv);
        i915_update_gfx_val(dev_priv);
+       if (INTEL_INFO(dev)->gen >= 6)
+               gen6_rps_busy(dev_priv);
        dev_priv->mm.busy = true;
 }
 
@@ -9214,9 +9425,6 @@ void intel_mark_idle(struct drm_device *dev)
 
        dev_priv->mm.busy = false;
 
-       if (!i915.powersave)
-               goto out;
-
        for_each_crtc(dev, crtc) {
                if (!crtc->primary->fb)
                        continue;
@@ -9227,7 +9435,6 @@ void intel_mark_idle(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen >= 6)
                gen6_rps_idle(dev->dev_private);
 
-out:
        intel_runtime_pm_put(dev_priv);
 }
 
@@ -9269,7 +9476,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
        enum pipe pipe = to_intel_crtc(work->crtc)->pipe;
 
        mutex_lock(&dev->struct_mutex);
-       intel_unpin_fb_obj(intel_fb_obj(work->old_fb));
+       intel_unpin_fb_obj(work->old_fb, work->crtc->primary->state);
        drm_gem_object_unreference(&work->pending_flip_obj->base);
 
        intel_fbc_update(dev);
@@ -9977,12 +10184,13 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                ring = &dev_priv->ring[RCS];
        }
 
-       ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, ring);
+       ret = intel_pin_and_fence_fb_obj(crtc->primary, fb,
+                                        crtc->primary->state, ring);
        if (ret)
                goto cleanup_pending;
 
-       work->gtt_offset =
-               i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
+       work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary), obj)
+                                                 + intel_crtc->dspaddr_offset;
 
        if (use_mmio_flip(ring, obj)) {
                ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring,
@@ -10017,7 +10225,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        return 0;
 
 cleanup_unpin:
-       intel_unpin_fb_obj(obj);
+       intel_unpin_fb_obj(fb, crtc->primary->state);
 cleanup_pending:
        atomic_dec(&intel_crtc->unpin_work_count);
        mutex_unlock(&dev->struct_mutex);
@@ -10087,6 +10295,27 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
        }
 }
 
+/* Transitional helper to copy current connector/encoder state to
+ * connector->state. This is needed so that code that is partially
+ * converted to atomic does the right thing.
+ */
+static void intel_modeset_update_connector_atomic_state(struct drm_device *dev)
+{
+       struct intel_connector *connector;
+
+       for_each_intel_connector(dev, connector) {
+               if (connector->base.encoder) {
+                       connector->base.state->best_encoder =
+                               connector->base.encoder;
+                       connector->base.state->crtc =
+                               connector->base.encoder->crtc;
+               } else {
+                       connector->base.state->best_encoder = NULL;
+                       connector->base.state->crtc = NULL;
+               }
+       }
+}
+
 /**
  * intel_modeset_commit_output_state
  *
@@ -10110,6 +10339,8 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
                crtc->base.state->enable = crtc->new_enabled;
                crtc->base.enabled = crtc->new_enabled;
        }
+
+       intel_modeset_update_connector_atomic_state(dev);
 }
 
 static void
@@ -10144,8 +10375,9 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc,
                          struct intel_crtc_state *pipe_config)
 {
        struct drm_device *dev = crtc->base.dev;
+       struct drm_atomic_state *state;
        struct intel_connector *connector;
-       int bpp;
+       int bpp, i;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_C8:
@@ -10185,10 +10417,15 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc,
 
        pipe_config->pipe_bpp = bpp;
 
+       state = pipe_config->base.state;
+
        /* Clamp display bpp to EDID value */
-       for_each_intel_connector(dev, connector) {
-               if (!connector->new_encoder ||
-                   connector->new_encoder->new_crtc != crtc)
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
+                       continue;
+
+               connector = to_intel_connector(state->connectors[i]);
+               if (state->connector_states[i]->crtc != &crtc->base)
                        continue;
 
                connected_sink_compute_bpp(connector, pipe_config);
@@ -10344,15 +10581,30 @@ static bool check_digital_port_conflicts(struct drm_device *dev)
        return true;
 }
 
+static void
+clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
+{
+       struct drm_crtc_state tmp_state;
+
+       /* Clear only the intel specific part of the crtc state */
+       tmp_state = crtc_state->base;
+       memset(crtc_state, 0, sizeof *crtc_state);
+       crtc_state->base = tmp_state;
+}
+
 static struct intel_crtc_state *
 intel_modeset_pipe_config(struct drm_crtc *crtc,
                          struct drm_framebuffer *fb,
-                         struct drm_display_mode *mode)
+                         struct drm_display_mode *mode,
+                         struct drm_atomic_state *state)
 {
        struct drm_device *dev = crtc->dev;
        struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       struct drm_connector_state *connector_state;
        struct intel_crtc_state *pipe_config;
        int plane_bpp, ret = -EINVAL;
+       int i;
        bool retry = true;
 
        if (!check_encoder_cloning(to_intel_crtc(crtc))) {
@@ -10365,9 +10617,11 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
                return ERR_PTR(-EINVAL);
        }
 
-       pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
-       if (!pipe_config)
-               return ERR_PTR(-ENOMEM);
+       pipe_config = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));
+       if (IS_ERR(pipe_config))
+               return pipe_config;
+
+       clear_intel_crtc_state(pipe_config);
 
        pipe_config->base.crtc = crtc;
        drm_mode_copy(&pipe_config->base.adjusted_mode, mode);
@@ -10424,11 +10678,17 @@ encoder_retry:
         * adjust it according to limitations or connector properties, and also
         * a chance to reject the mode entirely.
         */
-       for_each_intel_encoder(dev, encoder) {
+       for (i = 0; i < state->num_connector; i++) {
+               connector = to_intel_connector(state->connectors[i]);
+               if (!connector)
+                       continue;
 
-               if (&encoder->new_crtc->base != crtc)
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != crtc)
                        continue;
 
+               encoder = to_intel_encoder(connector_state->best_encoder);
+
                if (!(encoder->compute_config(encoder, pipe_config))) {
                        DRM_DEBUG_KMS("Encoder config failure\n");
                        goto fail;
@@ -10464,7 +10724,6 @@ encoder_retry:
 
        return pipe_config;
 fail:
-       kfree(pipe_config);
        return ERR_PTR(ret);
 }
 
@@ -11143,17 +11402,30 @@ static struct intel_crtc_state *
 intel_modeset_compute_config(struct drm_crtc *crtc,
                             struct drm_display_mode *mode,
                             struct drm_framebuffer *fb,
+                            struct drm_atomic_state *state,
                             unsigned *modeset_pipes,
                             unsigned *prepare_pipes,
                             unsigned *disable_pipes)
 {
+       struct drm_device *dev = crtc->dev;
        struct intel_crtc_state *pipe_config = NULL;
+       struct intel_crtc *intel_crtc;
+       int ret = 0;
+
+       ret = drm_atomic_add_affected_connectors(state, crtc);
+       if (ret)
+               return ERR_PTR(ret);
 
        intel_modeset_affected_pipes(crtc, modeset_pipes,
                                     prepare_pipes, disable_pipes);
 
-       if ((*modeset_pipes) == 0)
-               goto out;
+       for_each_intel_crtc_masked(dev, *disable_pipes, intel_crtc) {
+               pipe_config = intel_atomic_get_crtc_state(state, intel_crtc);
+               if (IS_ERR(pipe_config))
+                       return pipe_config;
+
+               pipe_config->base.enable = false;
+       }
 
        /*
         * Note this needs changes when we start tracking multiple modes
@@ -11161,15 +11433,21 @@ intel_modeset_compute_config(struct drm_crtc *crtc,
         * (i.e. one pipe_config for each crtc) rather than just the one
         * for this crtc.
         */
-       pipe_config = intel_modeset_pipe_config(crtc, fb, mode);
-       if (IS_ERR(pipe_config)) {
-               goto out;
+       for_each_intel_crtc_masked(dev, *modeset_pipes, intel_crtc) {
+               /* FIXME: For now we still expect modeset_pipes has at most
+                * one bit set. */
+               if (WARN_ON(&intel_crtc->base != crtc))
+                       continue;
+
+               pipe_config = intel_modeset_pipe_config(crtc, fb, mode, state);
+               if (IS_ERR(pipe_config))
+                       return pipe_config;
+
+               intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
+                                      "[modeset]");
        }
-       intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
-                              "[modeset]");
 
-out:
-       return pipe_config;
+       return intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));;
 }
 
 static int __intel_set_mode_setup_plls(struct drm_device *dev,
@@ -11213,6 +11491,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_display_mode *saved_mode;
+       struct intel_crtc_state *crtc_state_copy = NULL;
        struct intel_crtc *intel_crtc;
        int ret = 0;
 
@@ -11220,6 +11499,12 @@ static int __intel_set_mode(struct drm_crtc *crtc,
        if (!saved_mode)
                return -ENOMEM;
 
+       crtc_state_copy = kmalloc(sizeof(*crtc_state_copy), GFP_KERNEL);
+       if (!crtc_state_copy) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
        *saved_mode = crtc->mode;
 
        if (modeset_pipes)
@@ -11277,7 +11562,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
         * update the the output configuration. */
        intel_modeset_update_state(dev, prepare_pipes);
 
-       modeset_update_crtc_power_domains(dev);
+       modeset_update_crtc_power_domains(pipe_config->base.state);
 
        /* Set up the DPLL and any encoders state that needs to adjust or depend
         * on the DPLL.
@@ -11306,6 +11591,22 @@ done:
        if (ret && crtc->state->enable)
                crtc->mode = *saved_mode;
 
+       if (ret == 0 && pipe_config) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+               /* The pipe_config will be freed with the atomic state, so
+                * make a copy. */
+               memcpy(crtc_state_copy, intel_crtc->config,
+                      sizeof *crtc_state_copy);
+               intel_crtc->config = crtc_state_copy;
+               intel_crtc->base.state = &crtc_state_copy->base;
+
+               if (modeset_pipes)
+                       intel_crtc->new_config = intel_crtc->config;
+       } else {
+               kfree(crtc_state_copy);
+       }
+
        kfree(saved_mode);
        return ret;
 }
@@ -11331,27 +11632,81 @@ static int intel_set_mode_pipes(struct drm_crtc *crtc,
 
 static int intel_set_mode(struct drm_crtc *crtc,
                          struct drm_display_mode *mode,
-                         int x, int y, struct drm_framebuffer *fb)
+                         int x, int y, struct drm_framebuffer *fb,
+                         struct drm_atomic_state *state)
 {
        struct intel_crtc_state *pipe_config;
        unsigned modeset_pipes, prepare_pipes, disable_pipes;
+       int ret = 0;
 
-       pipe_config = intel_modeset_compute_config(crtc, mode, fb,
+       pipe_config = intel_modeset_compute_config(crtc, mode, fb, state,
                                                   &modeset_pipes,
                                                   &prepare_pipes,
                                                   &disable_pipes);
 
-       if (IS_ERR(pipe_config))
-               return PTR_ERR(pipe_config);
+       if (IS_ERR(pipe_config)) {
+               ret = PTR_ERR(pipe_config);
+               goto out;
+       }
+
+       ret = intel_set_mode_pipes(crtc, mode, x, y, fb, pipe_config,
+                                  modeset_pipes, prepare_pipes,
+                                  disable_pipes);
+       if (ret)
+               goto out;
 
-       return intel_set_mode_pipes(crtc, mode, x, y, fb, pipe_config,
-                                   modeset_pipes, prepare_pipes,
-                                   disable_pipes);
+out:
+       return ret;
 }
 
 void intel_crtc_restore_mode(struct drm_crtc *crtc)
 {
-       intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb);
+       struct drm_device *dev = crtc->dev;
+       struct drm_atomic_state *state;
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       struct drm_connector_state *connector_state;
+
+       state = drm_atomic_state_alloc(dev);
+       if (!state) {
+               DRM_DEBUG_KMS("[CRTC:%d] mode restore failed, out of memory",
+                             crtc->base.id);
+               return;
+       }
+
+       state->acquire_ctx = dev->mode_config.acquire_ctx;
+
+       /* The force restore path in the HW readout code relies on the staged
+        * config still keeping the user requested config while the actual
+        * state has been overwritten by the configuration read from HW. We
+        * need to copy the staged config to the atomic state, otherwise the
+        * mode set will just reapply the state the HW is already in. */
+       for_each_intel_encoder(dev, encoder) {
+               if (&encoder->new_crtc->base != crtc)
+                       continue;
+
+               for_each_intel_connector(dev, connector) {
+                       if (connector->new_encoder != encoder)
+                               continue;
+
+                       connector_state = drm_atomic_get_connector_state(state, &connector->base);
+                       if (IS_ERR(connector_state)) {
+                               DRM_DEBUG_KMS("Failed to add [CONNECTOR:%d:%s] to state: %ld\n",
+                                             connector->base.base.id,
+                                             connector->base.name,
+                                             PTR_ERR(connector_state));
+                               continue;
+                       }
+
+                       connector_state->crtc = crtc;
+                       connector_state->best_encoder = &encoder->base;
+               }
+       }
+
+       intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb,
+                      state);
+
+       drm_atomic_state_free(state);
 }
 
 #undef for_each_intel_crtc_masked
@@ -11520,9 +11875,11 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
 static int
 intel_modeset_stage_output_state(struct drm_device *dev,
                                 struct drm_mode_set *set,
-                                struct intel_set_config *config)
+                                struct intel_set_config *config,
+                                struct drm_atomic_state *state)
 {
        struct intel_connector *connector;
+       struct drm_connector_state *connector_state;
        struct intel_encoder *encoder;
        struct intel_crtc *crtc;
        int ro;
@@ -11586,6 +11943,14 @@ intel_modeset_stage_output_state(struct drm_device *dev,
                }
                connector->new_encoder->new_crtc = to_intel_crtc(new_crtc);
 
+               connector_state =
+                       drm_atomic_get_connector_state(state, &connector->base);
+               if (IS_ERR(connector_state))
+                       return PTR_ERR(connector_state);
+
+               connector_state->crtc = new_crtc;
+               connector_state->best_encoder = &connector->new_encoder->base;
+
                DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
                        connector->base.base.id,
                        connector->base.name,
@@ -11618,9 +11983,17 @@ intel_modeset_stage_output_state(struct drm_device *dev,
        }
        /* Now we've also updated encoder->new_crtc for all encoders. */
        for_each_intel_connector(dev, connector) {
-               if (connector->new_encoder)
+               connector_state =
+                       drm_atomic_get_connector_state(state, &connector->base);
+               if (IS_ERR(connector_state))
+                       return PTR_ERR(connector_state);
+
+               if (connector->new_encoder) {
                        if (connector->new_encoder != connector->encoder)
                                connector->encoder = connector->new_encoder;
+               } else {
+                       connector_state->crtc = NULL;
+               }
        }
        for_each_intel_crtc(dev, crtc) {
                crtc->new_enabled = false;
@@ -11676,6 +12049,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 {
        struct drm_device *dev;
        struct drm_mode_set save_set;
+       struct drm_atomic_state *state = NULL;
        struct intel_set_config *config;
        struct intel_crtc_state *pipe_config;
        unsigned modeset_pipes, prepare_pipes, disable_pipes;
@@ -11720,12 +12094,20 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
         * such cases. */
        intel_set_config_compute_mode_changes(set, config);
 
-       ret = intel_modeset_stage_output_state(dev, set, config);
+       state = drm_atomic_state_alloc(dev);
+       if (!state) {
+               ret = -ENOMEM;
+               goto out_config;
+       }
+
+       state->acquire_ctx = dev->mode_config.acquire_ctx;
+
+       ret = intel_modeset_stage_output_state(dev, set, config, state);
        if (ret)
                goto fail;
 
        pipe_config = intel_modeset_compute_config(set->crtc, set->mode,
-                                                  set->fb,
+                                                  set->fb, state,
                                                   &modeset_pipes,
                                                   &prepare_pipes,
                                                   &disable_pipes);
@@ -11745,10 +12127,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
                 */
        }
 
-       /* set_mode will free it in the mode_changed case */
-       if (!config->mode_changed)
-               kfree(pipe_config);
-
        intel_update_pipe_size(to_intel_crtc(set->crtc));
 
        if (config->mode_changed) {
@@ -11794,6 +12172,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 fail:
                intel_set_config_restore_state(dev, config);
 
+               drm_atomic_state_clear(state);
+
                /*
                 * HACK: if the pipe was on, but we didn't have a framebuffer,
                 * force the pipe off to avoid oopsing in the modeset code
@@ -11806,11 +12186,15 @@ fail:
                /* Try to restore the config */
                if (config->mode_changed &&
                    intel_set_mode(save_set.crtc, save_set.mode,
-                                  save_set.x, save_set.y, save_set.fb))
+                                  save_set.x, save_set.y, save_set.fb,
+                                  state))
                        DRM_ERROR("failed to restore config after modeset failure\n");
        }
 
 out_config:
+       if (state)
+               drm_atomic_state_free(state);
+
        intel_set_config_free(config);
        return ret;
 }
@@ -11925,6 +12309,28 @@ static void intel_shared_dpll_init(struct drm_device *dev)
 }
 
 /**
+ * intel_wm_need_update - Check whether watermarks need updating
+ * @plane: drm plane
+ * @state: new plane state
+ *
+ * Check current plane state versus the new one to determine whether
+ * watermarks need to be recalculated.
+ *
+ * Returns true or false.
+ */
+bool intel_wm_need_update(struct drm_plane *plane,
+                         struct drm_plane_state *state)
+{
+       /* Update watermarks on tiling changes. */
+       if (!plane->state->fb || !state->fb ||
+           plane->state->fb->modifier[0] != state->fb->modifier[0] ||
+           plane->state->rotation != state->rotation)
+               return true;
+
+       return false;
+}
+
+/**
  * intel_prepare_plane_fb - Prepare fb for usage on plane
  * @plane: drm plane to prepare for
  * @fb: framebuffer to prepare for presentation
@@ -11973,7 +12379,7 @@ intel_prepare_plane_fb(struct drm_plane *plane,
                if (ret)
                        DRM_DEBUG_KMS("failed to attach phys object\n");
        } else {
-               ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
+               ret = intel_pin_and_fence_fb_obj(plane, fb, new_state, NULL);
        }
 
        if (ret == 0)
@@ -12005,7 +12411,7 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
        if (plane->type != DRM_PLANE_TYPE_CURSOR ||
            !INTEL_INFO(dev)->cursor_needs_physical) {
                mutex_lock(&dev->struct_mutex);
-               intel_unpin_fb_obj(obj);
+               intel_unpin_fb_obj(fb, old_state);
                mutex_unlock(&dev->struct_mutex);
        }
 }
@@ -12070,10 +12476,7 @@ intel_check_primary_plane(struct drm_plane *plane,
 
                intel_crtc->atomic.update_fbc = true;
 
-               /* Update watermarks on tiling changes. */
-               if (!plane->state->fb || !state->base.fb ||
-                   plane->state->fb->modifier[0] !=
-                   state->base.fb->modifier[0])
+               if (intel_wm_need_update(plane, &state->base))
                        intel_crtc->atomic.update_wm = true;
        }
 
@@ -12089,8 +12492,6 @@ intel_commit_primary_plane(struct drm_plane *plane,
        struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-       struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_rect *src = &state->src;
 
        crtc = crtc ? crtc : plane->crtc;
@@ -12100,8 +12501,6 @@ intel_commit_primary_plane(struct drm_plane *plane,
        crtc->x = src->x1 >> 16;
        crtc->y = src->y1 >> 16;
 
-       intel_plane->obj = obj;
-
        if (intel_crtc->active) {
                if (state->visible) {
                        /* FIXME: kill this fastboot hack */
@@ -12365,7 +12764,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
        struct drm_crtc *crtc = state->base.crtc;
        struct drm_device *dev = plane->dev;
        struct intel_crtc *intel_crtc;
-       struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
        uint32_t addr;
 
@@ -12376,8 +12774,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
        crtc->cursor_x = state->base.crtc_x;
        crtc->cursor_y = state->base.crtc_y;
 
-       intel_plane->obj = obj;
-
        if (intel_crtc->cursor_bo == obj)
                goto update;
 
@@ -12758,19 +13154,21 @@ static void intel_setup_outputs(struct drm_device *dev)
         * testing/debug of the plane operations (and only when a specific
         * kernel module option is given), that shouldn't really matter.
         *
+        * We are also relying on these states to convert the legacy mode set
+        * to use a drm_atomic_state struct. The states are kept consistent
+        * with actual state, so that it is safe to rely on that instead of
+        * the staged config.
+        *
         * Once atomic support for crtc's + connectors lands, this loop should
         * be removed since we'll be setting up real connector state, which
         * will contain Intel-specific properties.
         */
-       if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
-               list_for_each_entry(connector,
-                                   &dev->mode_config.connector_list,
-                                   head) {
-                       if (!WARN_ON(connector->state)) {
-                               connector->state =
-                                       kzalloc(sizeof(*connector->state),
-                                               GFP_KERNEL);
-                       }
+       list_for_each_entry(connector,
+                           &dev->mode_config.connector_list,
+                           head) {
+               if (!WARN_ON(connector->state)) {
+                       connector->state = kzalloc(sizeof(*connector->state),
+                                                  GFP_KERNEL);
                }
        }
 
@@ -12849,7 +13247,7 @@ static int intel_framebuffer_init(struct drm_device *dev,
                                  struct drm_mode_fb_cmd2 *mode_cmd,
                                  struct drm_i915_gem_object *obj)
 {
-       int aligned_height;
+       unsigned int aligned_height;
        int ret;
        u32 pitch_limit, stride_alignment;
 
@@ -12885,8 +13283,8 @@ static int intel_framebuffer_init(struct drm_device *dev,
        case I915_FORMAT_MOD_X_TILED:
                break;
        default:
-               DRM_ERROR("Unsupported fb modifier 0x%llx!\n",
-                               mode_cmd->modifier[0]);
+               DRM_DEBUG("Unsupported fb modifier 0x%llx!\n",
+                         mode_cmd->modifier[0]);
                return -EINVAL;
        }
 
@@ -13453,7 +13851,7 @@ void intel_modeset_init(struct drm_device *dev)
                         * If the fb is shared between multiple heads, we'll
                         * just get the first one.
                         */
-                       intel_find_plane_obj(crtc, &crtc->plane_config);
+                       intel_find_initial_plane_obj(crtc, &crtc->plane_config);
                }
        }
 }
@@ -13479,7 +13877,7 @@ static void intel_enable_pipe_a(struct drm_device *dev)
                return;
 
        if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx))
-               intel_release_load_detect_pipe(crt, &load_detect_temp);
+               intel_release_load_detect_pipe(crt, &load_detect_temp, ctx);
 }
 
 static bool
@@ -13823,6 +14221,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                                       "[setup_hw_state]");
        }
 
+       intel_modeset_update_connector_atomic_state(dev);
+
        for (i = 0; i < dev_priv->num_shared_dpll; i++) {
                struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
 
@@ -13851,8 +14251,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                        struct drm_crtc *crtc =
                                dev_priv->pipe_to_crtc_mapping[pipe];
 
-                       intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
-                                      crtc->primary->fb);
+                       intel_crtc_restore_mode(crtc);
                }
        } else {
                intel_modeset_update_staged_output_state(dev);
@@ -13898,6 +14297,7 @@ void intel_modeset_gem_init(struct drm_device *dev)
 
                if (intel_pin_and_fence_fb_obj(c->primary,
                                               c->primary->fb,
+                                              c->primary->state,
                                               NULL)) {
                        DRM_ERROR("failed to pin boot fb on pipe %d\n",
                                  to_intel_crtc(c)->pipe);
index ca60060..b70e635 100644 (file)
@@ -85,10 +85,12 @@ static const struct dp_link_dpll chv_dpll[] = {
                { .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } }
 };
 /* Skylake supports following rates */
-static const uint32_t gen9_rates[] = { 162000, 216000, 270000, 324000,
-                                       432000, 540000 };
-
-static const uint32_t default_rates[] = { 162000, 270000, 540000 };
+static const int gen9_rates[] = { 162000, 216000, 270000,
+                                 324000, 432000, 540000 };
+static const int chv_rates[] = { 162000, 202500, 210000, 216000,
+                                243000, 270000, 324000, 405000,
+                                420000, 432000, 540000 };
+static const int default_rates[] = { 162000, 270000, 540000 };
 
 /**
  * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
@@ -123,26 +125,15 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp);
 static void vlv_steal_power_sequencer(struct drm_device *dev,
                                      enum pipe pipe);
 
-int
-intel_dp_max_link_bw(struct intel_dp *intel_dp)
+static int
+intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 {
        int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
-       struct drm_device *dev = intel_dp->attached_connector->base.dev;
 
        switch (max_link_bw) {
        case DP_LINK_BW_1_62:
        case DP_LINK_BW_2_7:
-               break;
-       case DP_LINK_BW_5_4: /* 1.2 capable displays may advertise higher bw */
-               if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0)
-                       /* WaDisableHBR2:skl */
-                       max_link_bw = DP_LINK_BW_2_7;
-               else if (((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) ||
-                    INTEL_INFO(dev)->gen >= 8) &&
-                   intel_dp->dpcd[DP_DPCD_REV] >= 0x12)
-                       max_link_bw = DP_LINK_BW_5_4;
-               else
-                       max_link_bw = DP_LINK_BW_2_7;
+       case DP_LINK_BW_5_4:
                break;
        default:
                WARN(1, "invalid max DP link bw val %x, using 1.62Gbps\n",
@@ -218,7 +209,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
                target_clock = fixed_mode->clock;
        }
 
-       max_link_clock = drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp));
+       max_link_clock = intel_dp_max_link_rate(intel_dp);
        max_lanes = intel_dp_max_lane_count(intel_dp);
 
        max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
@@ -951,8 +942,9 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        size_t txsize, rxsize;
        int ret;
 
-       txbuf[0] = msg->request << 4;
-       txbuf[1] = msg->address >> 8;
+       txbuf[0] = (msg->request << 4) |
+               ((msg->address >> 16) & 0xf);
+       txbuf[1] = (msg->address >> 8) & 0xff;
        txbuf[2] = msg->address & 0xff;
        txbuf[3] = msg->size - 1;
 
@@ -960,7 +952,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        case DP_AUX_NATIVE_WRITE:
        case DP_AUX_I2C_WRITE:
                txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
-               rxsize = 1;
+               rxsize = 2; /* 0 or 1 data bytes */
 
                if (WARN_ON(txsize > 20))
                        return -E2BIG;
@@ -971,8 +963,13 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                if (ret > 0) {
                        msg->reply = rxbuf[0] >> 4;
 
-                       /* Return payload size. */
-                       ret = msg->size;
+                       if (ret > 1) {
+                               /* Number of bytes written in a short write. */
+                               ret = clamp_t(int, rxbuf[1], 0, msg->size);
+                       } else {
+                               /* Return payload size. */
+                               ret = msg->size;
+                       }
                }
                break;
 
@@ -1142,49 +1139,39 @@ hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw)
 }
 
 static int
-intel_read_sink_rates(struct intel_dp *intel_dp, uint32_t *sink_rates)
+intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
 {
-       struct drm_device *dev = intel_dp_to_dev(intel_dp);
-       int i = 0;
-       uint16_t val;
-
-       if (INTEL_INFO(dev)->gen >= 9 && intel_dp->supported_rates[0]) {
-               /*
-                * Receiver supports only main-link rate selection by
-                * link rate table method, so read link rates from
-                * supported_link_rates
-                */
-               for (i = 0; i < DP_MAX_SUPPORTED_RATES; ++i) {
-                       val = le16_to_cpu(intel_dp->supported_rates[i]);
-                       if (val == 0)
-                               break;
+       if (intel_dp->num_sink_rates) {
+               *sink_rates = intel_dp->sink_rates;
+               return intel_dp->num_sink_rates;
+       }
 
-                       sink_rates[i] = val * 200;
-               }
+       *sink_rates = default_rates;
 
-               if (i <= 0)
-                       DRM_ERROR("No rates in SUPPORTED_LINK_RATES");
-       }
-       return i;
+       return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
 }
 
 static int
-intel_read_source_rates(struct intel_dp *intel_dp, uint32_t *source_rates)
+intel_dp_source_rates(struct drm_device *dev, const int **source_rates)
 {
-       struct drm_device *dev = intel_dp_to_dev(intel_dp);
-       int i;
-       int max_default_rate;
-
-       if (INTEL_INFO(dev)->gen >= 9 && intel_dp->supported_rates[0]) {
-               for (i = 0; i < ARRAY_SIZE(gen9_rates); ++i)
-                       source_rates[i] = gen9_rates[i];
-       } else {
-               /* Index of the max_link_bw supported + 1 */
-               max_default_rate = (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
-               for (i = 0; i < max_default_rate; ++i)
-                       source_rates[i] = default_rates[i];
+       if (INTEL_INFO(dev)->gen >= 9) {
+               *source_rates = gen9_rates;
+               return ARRAY_SIZE(gen9_rates);
+       } else if (IS_CHERRYVIEW(dev)) {
+               *source_rates = chv_rates;
+               return ARRAY_SIZE(chv_rates);
        }
-       return i;
+
+       *source_rates = default_rates;
+
+       if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0)
+               /* WaDisableHBR2:skl */
+               return (DP_LINK_BW_2_7 >> 3) + 1;
+       else if (INTEL_INFO(dev)->gen >= 8 ||
+           (IS_HASWELL(dev) && !IS_HSW_ULX(dev)))
+               return (DP_LINK_BW_5_4 >> 3) + 1;
+       else
+               return (DP_LINK_BW_2_7 >> 3) + 1;
 }
 
 static void
@@ -1220,22 +1207,17 @@ intel_dp_set_clock(struct intel_encoder *encoder,
        }
 }
 
-static int intel_supported_rates(const uint32_t *source_rates, int source_len,
-const uint32_t *sink_rates, int sink_len, uint32_t *supported_rates)
+static int intersect_rates(const int *source_rates, int source_len,
+                          const int *sink_rates, int sink_len,
+                          int *common_rates)
 {
        int i = 0, j = 0, k = 0;
 
-       /* For panels with edp version less than 1.4 */
-       if (sink_len == 0) {
-               for (i = 0; i < source_len; ++i)
-                       supported_rates[i] = source_rates[i];
-               return source_len;
-       }
-
-       /* For edp1.4 panels, find the common rates between source and sink */
        while (i < source_len && j < sink_len) {
                if (source_rates[i] == sink_rates[j]) {
-                       supported_rates[k] = source_rates[i];
+                       if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
+                               return k;
+                       common_rates[k] = source_rates[i];
                        ++k;
                        ++i;
                        ++j;
@@ -1248,7 +1230,62 @@ const uint32_t *sink_rates, int sink_len, uint32_t *supported_rates)
        return k;
 }
 
-static int rate_to_index(uint32_t find, const uint32_t *rates)
+static int intel_dp_common_rates(struct intel_dp *intel_dp,
+                                int *common_rates)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       const int *source_rates, *sink_rates;
+       int source_len, sink_len;
+
+       sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+       source_len = intel_dp_source_rates(dev, &source_rates);
+
+       return intersect_rates(source_rates, source_len,
+                              sink_rates, sink_len,
+                              common_rates);
+}
+
+static void snprintf_int_array(char *str, size_t len,
+                              const int *array, int nelem)
+{
+       int i;
+
+       str[0] = '\0';
+
+       for (i = 0; i < nelem; i++) {
+               int r = snprintf(str, len, "%d,", array[i]);
+               if (r >= len)
+                       return;
+               str += r;
+               len -= r;
+       }
+}
+
+static void intel_dp_print_rates(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       const int *source_rates, *sink_rates;
+       int source_len, sink_len, common_len;
+       int common_rates[DP_MAX_SUPPORTED_RATES];
+       char str[128]; /* FIXME: too big for stack? */
+
+       if ((drm_debug & DRM_UT_KMS) == 0)
+               return;
+
+       source_len = intel_dp_source_rates(dev, &source_rates);
+       snprintf_int_array(str, sizeof(str), source_rates, source_len);
+       DRM_DEBUG_KMS("source rates: %s\n", str);
+
+       sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+       snprintf_int_array(str, sizeof(str), sink_rates, sink_len);
+       DRM_DEBUG_KMS("sink rates: %s\n", str);
+
+       common_len = intel_dp_common_rates(intel_dp, common_rates);
+       snprintf_int_array(str, sizeof(str), common_rates, common_len);
+       DRM_DEBUG_KMS("common rates: %s\n", str);
+}
+
+static int rate_to_index(int find, const int *rates)
 {
        int i = 0;
 
@@ -1259,6 +1296,24 @@ static int rate_to_index(uint32_t find, const uint32_t *rates)
        return i;
 }
 
+int
+intel_dp_max_link_rate(struct intel_dp *intel_dp)
+{
+       int rates[DP_MAX_SUPPORTED_RATES] = {};
+       int len;
+
+       len = intel_dp_common_rates(intel_dp, rates);
+       if (WARN_ON(len <= 0))
+               return 162000;
+
+       return rates[rate_to_index(0, rates) - 1];
+}
+
+int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
+{
+       return rate_to_index(rate, intel_dp->sink_rates);
+}
+
 bool
 intel_dp_compute_config(struct intel_encoder *encoder,
                        struct intel_crtc_state *pipe_config)
@@ -1268,7 +1323,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
-       struct intel_crtc *intel_crtc = encoder->new_crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
        struct intel_connector *intel_connector = intel_dp->attached_connector;
        int lane_count, clock;
        int min_lane_count = 1;
@@ -1278,22 +1333,15 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        int max_clock;
        int bpp, mode_rate;
        int link_avail, link_clock;
-       uint32_t sink_rates[8];
-       uint32_t supported_rates[8] = {0};
-       uint32_t source_rates[8];
-       int source_len, sink_len, supported_len;
-
-       sink_len = intel_read_sink_rates(intel_dp, sink_rates);
+       int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+       int common_len;
 
-       source_len = intel_read_source_rates(intel_dp, source_rates);
-
-       supported_len = intel_supported_rates(source_rates, source_len,
-                               sink_rates, sink_len, supported_rates);
+       common_len = intel_dp_common_rates(intel_dp, common_rates);
 
        /* No common link rates between source and sink */
-       WARN_ON(supported_len <= 0);
+       WARN_ON(common_len <= 0);
 
-       max_clock = supported_len - 1;
+       max_clock = common_len - 1;
 
        if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A)
                pipe_config->has_pch_encoder = true;
@@ -1318,7 +1366,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 
        DRM_DEBUG_KMS("DP link computation with max lane count %i "
                      "max bw %d pixel clock %iKHz\n",
-                     max_lane_count, supported_rates[max_clock],
+                     max_lane_count, common_rates[max_clock],
                      adjusted_mode->crtc_clock);
 
        /* Walk through all bpp values. Luckily they're all nicely spaced with 2
@@ -1351,7 +1399,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                                lane_count <= max_lane_count;
                                lane_count <<= 1) {
 
-                               link_clock = supported_rates[clock];
+                               link_clock = common_rates[clock];
                                link_avail = intel_dp_max_data_rate(link_clock,
                                                                    lane_count);
 
@@ -1382,17 +1430,18 @@ found:
 
        intel_dp->lane_count = lane_count;
 
-       intel_dp->link_bw =
-               drm_dp_link_rate_to_bw_code(supported_rates[clock]);
-
-       if (INTEL_INFO(dev)->gen >= 9 && intel_dp->supported_rates[0]) {
-               intel_dp->rate_select =
-                       rate_to_index(supported_rates[clock], sink_rates);
+       if (intel_dp->num_sink_rates) {
                intel_dp->link_bw = 0;
+               intel_dp->rate_select =
+                       intel_dp_rate_select(intel_dp, common_rates[clock]);
+       } else {
+               intel_dp->link_bw =
+                       drm_dp_link_rate_to_bw_code(common_rates[clock]);
+               intel_dp->rate_select = 0;
        }
 
        pipe_config->pipe_bpp = bpp;
-       pipe_config->port_clock = supported_rates[clock];
+       pipe_config->port_clock = common_rates[clock];
 
        DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n",
                      intel_dp->link_bw, intel_dp->lane_count,
@@ -1415,7 +1464,7 @@ found:
        }
 
        if (IS_SKYLAKE(dev) && is_edp(intel_dp))
-               skl_edp_set_pll_config(pipe_config, supported_rates[clock]);
+               skl_edp_set_pll_config(pipe_config, common_rates[clock]);
        else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                hsw_dp_set_ddi_pll_sel(pipe_config, intel_dp->link_bw);
        else
@@ -3502,7 +3551,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
        if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
                link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
        drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
-       if (INTEL_INFO(dev)->gen >= 9 && intel_dp->supported_rates[0])
+       if (intel_dp->num_sink_rates)
                drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
                                &intel_dp->rate_select, 1);
 
@@ -3754,11 +3803,27 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
            (intel_dp->dpcd[DP_EDP_CONFIGURATION_CAP] & DP_DPCD_DISPLAY_CONTROL_CAPABLE) &&
            (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_EDP_DPCD_REV, &rev, 1) == 1) &&
            (rev >= 0x03)) { /* eDp v1.4 or higher */
+               __le16 sink_rates[DP_MAX_SUPPORTED_RATES];
+               int i;
+
                intel_dp_dpcd_read_wake(&intel_dp->aux,
                                DP_SUPPORTED_LINK_RATES,
-                               intel_dp->supported_rates,
-                               sizeof(intel_dp->supported_rates));
+                               sink_rates,
+                               sizeof(sink_rates));
+
+               for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
+                       int val = le16_to_cpu(sink_rates[i]);
+
+                       if (val == 0)
+                               break;
+
+                       intel_dp->sink_rates[i] = val * 200;
+               }
+               intel_dp->num_sink_rates = i;
        }
+
+       intel_dp_print_rates(intel_dp);
+
        if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
              DP_DWN_STRM_PORT_PRESENT))
                return true; /* native DP sink */
@@ -4548,6 +4613,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_dp_connector_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
@@ -4934,7 +5000,7 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
 
        dig_port = dp_to_dig_port(intel_dp);
        encoder = &dig_port->base;
-       intel_crtc = encoder->new_crtc;
+       intel_crtc = to_intel_crtc(encoder->base.crtc);
 
        if (!intel_crtc) {
                DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n");
@@ -5272,8 +5338,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        struct edid *edid;
        enum pipe pipe = INVALID_PIPE;
 
-       dev_priv->drrs.type = DRRS_NOT_SUPPORTED;
-
        if (!is_edp(intel_dp))
                return true;
 
index be12492..5329c85 100644 (file)
@@ -36,11 +36,11 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
        struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
        struct intel_digital_port *intel_dig_port = intel_mst->primary;
        struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_device *dev = encoder->base.dev;
-       int bpp;
-       int lane_count, slots;
+       struct drm_atomic_state *state;
+       int bpp, i;
+       int lane_count, slots, rate;
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct intel_connector *found = NULL, *intel_connector;
+       struct intel_connector *found = NULL;
        int mst_pbn;
 
        pipe_config->dp_encoder_is_mst = true;
@@ -52,15 +52,30 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
         * seem to suggest we should do otherwise.
         */
        lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
-       intel_dp->link_bw = intel_dp_max_link_bw(intel_dp);
+
+       rate = intel_dp_max_link_rate(intel_dp);
+
+       if (intel_dp->num_sink_rates) {
+               intel_dp->link_bw = 0;
+               intel_dp->rate_select = intel_dp_rate_select(intel_dp, rate);
+       } else {
+               intel_dp->link_bw = drm_dp_link_rate_to_bw_code(rate);
+               intel_dp->rate_select = 0;
+       }
+
        intel_dp->lane_count = lane_count;
 
        pipe_config->pipe_bpp = 24;
-       pipe_config->port_clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
+       pipe_config->port_clock = rate;
 
-       for_each_intel_connector(dev, intel_connector) {
-               if (intel_connector->new_encoder == encoder) {
-                       found = intel_connector;
+       state = pipe_config->base.state;
+
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
+                       continue;
+
+               if (state->connector_states[i]->best_encoder == &encoder->base) {
+                       found = to_intel_connector(state->connectors[i]);
                        break;
                }
        }
@@ -317,6 +332,7 @@ static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_dp_mst_connector_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static int intel_dp_mst_get_modes(struct drm_connector *connector)
index c77128c..6036e3b 100644 (file)
@@ -35,6 +35,7 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_atomic.h>
 
 #define DIV_ROUND_CLOSEST_ULL(ll, d)   \
 ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
@@ -56,8 +57,8 @@
                                ret__ = -ETIMEDOUT;                     \
                        break;                                          \
                }                                                       \
-               if (W && drm_can_sleep())  {                            \
-                       msleep(W);                                      \
+               if ((W) && drm_can_sleep()) {                           \
+                       usleep_range((W)*1000, (W)*2000);               \
                } else {                                                \
                        cpu_relax();                                    \
                }                                                       \
@@ -501,16 +502,19 @@ struct intel_plane_wm_parameters {
        bool enabled;
        bool scaled;
        u64 tiling;
+       unsigned int rotation;
 };
 
 struct intel_plane {
        struct drm_plane base;
        int plane;
        enum pipe pipe;
-       struct drm_i915_gem_object *obj;
        bool can_scale;
        int max_downscale;
 
+       /* FIXME convert to properties */
+       struct drm_intel_sprite_colorkey ckey;
+
        /* Since we need to change the watermarks before/after
         * enabling/disabling the planes, we need to store the parameters here
         * as the other pieces of the struct may not reflect the values we want
@@ -527,7 +531,6 @@ struct intel_plane {
        void (*update_plane)(struct drm_plane *plane,
                             struct drm_crtc *crtc,
                             struct drm_framebuffer *fb,
-                            struct drm_i915_gem_object *obj,
                             int crtc_x, int crtc_y,
                             unsigned int crtc_w, unsigned int crtc_h,
                             uint32_t x, uint32_t y,
@@ -538,10 +541,6 @@ struct intel_plane {
                           struct intel_plane_state *state);
        void (*commit_plane)(struct drm_plane *plane,
                             struct intel_plane_state *state);
-       int (*update_colorkey)(struct drm_plane *plane,
-                              struct drm_intel_sprite_colorkey *key);
-       void (*get_colorkey)(struct drm_plane *plane,
-                            struct drm_intel_sprite_colorkey *key);
 };
 
 struct intel_watermark_params {
@@ -564,6 +563,7 @@ struct cxsr_latency {
 };
 
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
+#define to_intel_crtc_state(x) container_of(x, struct intel_crtc_state, base)
 #define to_intel_connector(x) container_of(x, struct intel_connector, base)
 #define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
@@ -627,7 +627,9 @@ struct intel_dp {
        uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
        uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
        uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
-       __le16 supported_rates[DP_MAX_SUPPORTED_RATES];
+       /* sink rates as reported by DP_SUPPORTED_LINK_RATES */
+       uint8_t num_sink_rates;
+       int sink_rates[DP_MAX_SUPPORTED_RATES];
        struct drm_dp_aux aux;
        uint8_t train_set[4];
        int panel_power_up_delay;
@@ -902,9 +904,10 @@ void intel_frontbuffer_flip(struct drm_device *dev,
        intel_frontbuffer_flush(dev, frontbuffer_bits);
 }
 
-int intel_fb_align_height(struct drm_device *dev, int height,
-                         uint32_t pixel_format,
-                         uint64_t fb_format_modifier);
+unsigned int intel_fb_align_height(struct drm_device *dev,
+                                  unsigned int height,
+                                  uint32_t pixel_format,
+                                  uint64_t fb_format_modifier);
 void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
 
 u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier,
@@ -956,9 +959,11 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
                                struct intel_load_detect_pipe *old,
                                struct drm_modeset_acquire_ctx *ctx);
 void intel_release_load_detect_pipe(struct drm_connector *connector,
-                                   struct intel_load_detect_pipe *old);
+                                   struct intel_load_detect_pipe *old,
+                                   struct drm_modeset_acquire_ctx *ctx);
 int intel_pin_and_fence_fb_obj(struct drm_plane *plane,
                               struct drm_framebuffer *fb,
+                              const struct drm_plane_state *plane_state,
                               struct intel_engine_cs *pipelined);
 struct drm_framebuffer *
 __intel_framebuffer_create(struct drm_device *dev,
@@ -983,6 +988,19 @@ int intel_plane_atomic_set_property(struct drm_plane *plane,
                                    struct drm_property *property,
                                    uint64_t val);
 
+unsigned int
+intel_tile_height(struct drm_device *dev, uint32_t pixel_format,
+                 uint64_t fb_format_modifier);
+
+static inline bool
+intel_rotation_90_or_270(unsigned int rotation)
+{
+       return rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270));
+}
+
+bool intel_wm_need_update(struct drm_plane *plane,
+                         struct drm_plane_state *state);
+
 /* shared dpll functions */
 struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
 void assert_shared_dpll(struct drm_i915_private *dev_priv,
@@ -1037,6 +1055,9 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
 void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
 void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
 
+unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
+                                    struct drm_i915_gem_object *obj);
+
 /* intel_dp.c */
 void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
 bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
@@ -1060,7 +1081,8 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector);
 void intel_dp_mst_suspend(struct drm_device *dev);
 void intel_dp_mst_resume(struct drm_device *dev);
-int intel_dp_max_link_bw(struct intel_dp *intel_dp);
+int intel_dp_max_link_rate(struct intel_dp *intel_dp);
+int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
 void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
 void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
 uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
@@ -1239,6 +1261,8 @@ void intel_disable_gt_powersave(struct drm_device *dev);
 void intel_suspend_gt_powersave(struct drm_device *dev);
 void intel_reset_gt_powersave(struct drm_device *dev);
 void gen6_update_ring_freq(struct drm_device *dev);
+void gen6_rps_busy(struct drm_i915_private *dev_priv);
+void gen6_rps_reset_ei(struct drm_i915_private *dev_priv);
 void gen6_rps_idle(struct drm_i915_private *dev_priv);
 void gen6_rps_boost(struct drm_i915_private *dev_priv);
 void ilk_wm_get_hw_state(struct drm_device *dev);
@@ -1258,8 +1282,6 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
 int intel_plane_restore(struct drm_plane *plane);
 int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
-int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
-                             struct drm_file *file_priv);
 bool intel_pipe_update_start(struct intel_crtc *crtc,
                             uint32_t *start_vbl_count);
 void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count);
@@ -1282,6 +1304,17 @@ int intel_connector_atomic_get_property(struct drm_connector *connector,
 struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc);
 void intel_crtc_destroy_state(struct drm_crtc *crtc,
                               struct drm_crtc_state *state);
+static inline struct intel_crtc_state *
+intel_atomic_get_crtc_state(struct drm_atomic_state *state,
+                           struct intel_crtc *crtc)
+{
+       struct drm_crtc_state *crtc_state;
+       crtc_state = drm_atomic_get_crtc_state(state, &crtc->base);
+       if (IS_ERR(crtc_state))
+               return ERR_PTR(PTR_ERR(crtc_state));
+
+       return to_intel_crtc_state(crtc_state);
+}
 
 /* intel_atomic_plane.c */
 struct intel_plane_state *intel_create_plane_state(struct drm_plane *plane);
index c8c8b24..572251e 100644 (file)
@@ -975,6 +975,7 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = {
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_get_property = intel_connector_atomic_get_property,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 void intel_dsi_init(struct drm_device *dev)
index d857951..4ccd6c3 100644 (file)
@@ -393,6 +393,7 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = {
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_get_property = intel_connector_atomic_get_property,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
index 9fcf446..4165ce0 100644 (file)
@@ -521,7 +521,7 @@ void intel_fbc_update(struct drm_device *dev)
                goto out_disable;
        }
 
-       if (!i915.enable_fbc || !i915.powersave) {
+       if (!i915.enable_fbc) {
                if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
                        DRM_DEBUG_KMS("fbc disabled per module param\n");
                goto out_disable;
index 757c0d2..4e7e7da 100644 (file)
@@ -151,7 +151,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
        }
 
        /* Flush everything out, we'll be doing GTT only from now on */
-       ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL);
+       ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL);
        if (ret) {
                DRM_ERROR("failed to pin obj: %d\n", ret);
                goto out_fb;
index 0a1bac8..a20cffb 100644 (file)
@@ -110,9 +110,6 @@ static void intel_mark_fb_busy(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe;
 
-       if (!i915.powersave)
-               return;
-
        for_each_pipe(dev_priv, pipe) {
                if (!(frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe)))
                        continue;
index 995c5b2..cacbafd 100644 (file)
@@ -951,19 +951,30 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
-static bool hdmi_12bpc_possible(struct intel_crtc *crtc)
+static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
+       struct drm_atomic_state *state;
        struct intel_encoder *encoder;
+       struct drm_connector_state *connector_state;
        int count = 0, count_hdmi = 0;
+       int i;
 
        if (HAS_GMCH_DISPLAY(dev))
                return false;
 
-       for_each_intel_encoder(dev, encoder) {
-               if (encoder->new_crtc != crtc)
+       state = crtc_state->base.state;
+
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
                        continue;
 
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != crtc_state->base.crtc)
+                       continue;
+
+               encoder = to_intel_encoder(connector_state->best_encoder);
+
                count_hdmi += encoder->type == INTEL_OUTPUT_HDMI;
                count++;
        }
@@ -1020,7 +1031,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
         */
        if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink &&
            clock_12bpc <= portclock_limit &&
-           hdmi_12bpc_possible(encoder->new_crtc)) {
+           hdmi_12bpc_possible(pipe_config)) {
                DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
                desired_bpp = 12*3;
 
@@ -1618,6 +1629,7 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_hdmi_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
index 24e8730..06d2da3 100644 (file)
@@ -286,7 +286,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
        struct intel_connector *intel_connector =
                &lvds_encoder->attached_connector->base;
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
        unsigned int lvds_bpp;
 
        /* Should never happen!! */
@@ -535,6 +535,7 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_lvds_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
index 823d1d9..dd92122 100644 (file)
@@ -720,7 +720,8 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
        if (ret != 0)
                return ret;
 
-       ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL);
+       ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL,
+                                                  &i915_ggtt_view_normal);
        if (ret != 0)
                return ret;
 
index 288c9d2..fa4ccb3 100644 (file)
@@ -2840,6 +2840,7 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
                }
                p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w;
                p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h;
+               p->plane[0].rotation = crtc->primary->state->rotation;
 
                fb = crtc->cursor->state->fb;
                if (fb) {
@@ -2897,7 +2898,21 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 
        if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
            p_params->tiling == I915_FORMAT_MOD_Yf_TILED) {
-               uint32_t y_tile_minimum = plane_blocks_per_line * 4;
+               uint32_t min_scanlines = 4;
+               uint32_t y_tile_minimum;
+               if (intel_rotation_90_or_270(p_params->rotation)) {
+                       switch (p_params->bytes_per_pixel) {
+                       case 1:
+                               min_scanlines = 16;
+                               break;
+                       case 2:
+                               min_scanlines = 8;
+                               break;
+                       case 8:
+                               WARN(1, "Unsupported pixel depth for rotation");
+                       }
+               }
+               y_tile_minimum = plane_blocks_per_line * min_scanlines;
                selected_result = max(method2, y_tile_minimum);
        } else {
                if ((ddb_allocation / plane_blocks_per_line) >= 1)
@@ -3357,6 +3372,7 @@ skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc,
         */
        if (fb)
                intel_plane->wm.tiling = fb->modifier[0];
+       intel_plane->wm.rotation = plane->state->rotation;
 
        skl_update_wm(crtc);
 }
@@ -3855,9 +3871,9 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
                break;
        }
        /* Max/min bins are special */
-       if (val == dev_priv->rps.min_freq_softlimit)
+       if (val <= dev_priv->rps.min_freq_softlimit)
                new_power = LOW_POWER;
-       if (val == dev_priv->rps.max_freq_softlimit)
+       if (val >= dev_priv->rps.max_freq_softlimit)
                new_power = HIGH_POWER;
        if (new_power == dev_priv->rps.power)
                return;
@@ -3922,11 +3938,10 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
        u32 mask = 0;
 
        if (val > dev_priv->rps.min_freq_softlimit)
-               mask |= GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
+               mask |= GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
        if (val < dev_priv->rps.max_freq_softlimit)
-               mask |= GEN6_PM_RP_UP_THRESHOLD;
+               mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD;
 
-       mask |= dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED);
        mask &= dev_priv->pm_rps_events;
 
        return gen6_sanitize_rps_pm_mask(dev_priv, ~mask);
@@ -3940,8 +3955,8 @@ static void gen6_set_rps(struct drm_device *dev, u8 val)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-       WARN_ON(val > dev_priv->rps.max_freq_softlimit);
-       WARN_ON(val < dev_priv->rps.min_freq_softlimit);
+       WARN_ON(val > dev_priv->rps.max_freq);
+       WARN_ON(val < dev_priv->rps.min_freq);
 
        /* min/max delay may still have been modified so be sure to
         * write the limits value.
@@ -3979,8 +3994,8 @@ static void valleyview_set_rps(struct drm_device *dev, u8 val)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-       WARN_ON(val > dev_priv->rps.max_freq_softlimit);
-       WARN_ON(val < dev_priv->rps.min_freq_softlimit);
+       WARN_ON(val > dev_priv->rps.max_freq);
+       WARN_ON(val < dev_priv->rps.min_freq);
 
        if (WARN_ONCE(IS_CHERRYVIEW(dev) && (val & 1),
                      "Odd GPU freq value\n"))
@@ -4007,10 +4022,11 @@ static void valleyview_set_rps(struct drm_device *dev, u8 val)
 static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
+       u32 val = dev_priv->rps.idle_freq;
 
        /* CHV and latest VLV don't need to force the gfx clock */
        if (IS_CHERRYVIEW(dev) || dev->pdev->revision >= 0xd) {
-               valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+               valleyview_set_rps(dev_priv->dev, val);
                return;
        }
 
@@ -4018,7 +4034,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
         * When we are idle.  Drop to min voltage state.
         */
 
-       if (dev_priv->rps.cur_freq <= dev_priv->rps.min_freq_softlimit)
+       if (dev_priv->rps.cur_freq <= val)
                return;
 
        /* Mask turbo interrupt so that they will not come in between */
@@ -4027,10 +4043,9 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
 
        vlv_force_gfx_clock(dev_priv, true);
 
-       dev_priv->rps.cur_freq = dev_priv->rps.min_freq_softlimit;
+       dev_priv->rps.cur_freq = val;
 
-       vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ,
-                                       dev_priv->rps.min_freq_softlimit);
+       vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
 
        if (wait_for(((vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS))
                                & GENFREQSTATUS) == 0, 100))
@@ -4038,8 +4053,19 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
 
        vlv_force_gfx_clock(dev_priv, false);
 
-       I915_WRITE(GEN6_PMINTRMSK,
-                  gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
+       I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
+}
+
+void gen6_rps_busy(struct drm_i915_private *dev_priv)
+{
+       mutex_lock(&dev_priv->rps.hw_lock);
+       if (dev_priv->rps.enabled) {
+               if (dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED))
+                       gen6_rps_reset_ei(dev_priv);
+               I915_WRITE(GEN6_PMINTRMSK,
+                          gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
+       }
+       mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
 void gen6_rps_idle(struct drm_i915_private *dev_priv)
@@ -4051,17 +4077,23 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
                if (IS_VALLEYVIEW(dev))
                        vlv_set_rps_idle(dev_priv);
                else
-                       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+                       gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
                dev_priv->rps.last_adj = 0;
+               I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
 void gen6_rps_boost(struct drm_i915_private *dev_priv)
 {
+       u32 val;
+
        mutex_lock(&dev_priv->rps.hw_lock);
-       if (dev_priv->rps.enabled) {
-               intel_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
+       val = dev_priv->rps.max_freq_softlimit;
+       if (dev_priv->rps.enabled &&
+           dev_priv->mm.busy &&
+           dev_priv->rps.cur_freq < val) {
+               intel_set_rps(dev_priv->dev, val);
                dev_priv->rps.last_adj = 0;
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -4209,6 +4241,8 @@ static void gen6_init_rps_frequencies(struct drm_device *dev)
                                        dev_priv->rps.max_freq);
        }
 
+       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
        /* Preserve min/max settings in case of re-init */
        if (dev_priv->rps.max_freq_softlimit == 0)
                dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
@@ -4375,7 +4409,7 @@ static void gen8_enable_rps(struct drm_device *dev)
        /* 6: Ring frequency + overclocking (our driver does this later */
 
        dev_priv->rps.power = HIGH_POWER; /* force a reset */
-       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+       gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
@@ -4469,7 +4503,7 @@ static void gen6_enable_rps(struct drm_device *dev)
        }
 
        dev_priv->rps.power = HIGH_POWER; /* force a reset */
-       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+       gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
 
        rc6vids = 0;
        ret = sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids);
@@ -4834,6 +4868,8 @@ static void valleyview_init_gt_powersave(struct drm_device *dev)
                         intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
                         dev_priv->rps.min_freq);
 
+       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
        /* Preserve min/max settings in case of re-init */
        if (dev_priv->rps.max_freq_softlimit == 0)
                dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
@@ -4909,6 +4945,8 @@ static void cherryview_init_gt_powersave(struct drm_device *dev)
                   dev_priv->rps.min_freq) & 1,
                  "Odd GPU freq values\n");
 
+       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
        /* Preserve min/max settings in case of re-init */
        if (dev_priv->rps.max_freq_softlimit == 0)
                dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
@@ -5686,6 +5724,13 @@ static void intel_gen6_powersave_work(struct work_struct *work)
                gen6_enable_rps(dev);
                __gen6_update_ring_freq(dev);
        }
+
+       WARN_ON(dev_priv->rps.max_freq < dev_priv->rps.min_freq);
+       WARN_ON(dev_priv->rps.idle_freq > dev_priv->rps.max_freq);
+
+       WARN_ON(dev_priv->rps.efficient_freq < dev_priv->rps.min_freq);
+       WARN_ON(dev_priv->rps.efficient_freq > dev_priv->rps.max_freq);
+
        dev_priv->rps.enabled = true;
 
        gen6_enable_rps_interrupts(dev);
index b9f40c2..a8f9348 100644 (file)
@@ -532,8 +532,6 @@ static void intel_psr_exit(struct drm_device *dev)
                WARN_ON(!(val & EDP_PSR_ENABLE));
 
                I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE);
-
-               dev_priv->psr.active = false;
        } else {
                val = I915_READ(VLV_PSRCTL(pipe));
 
index 9e554c2..f5b7e1e 100644 (file)
@@ -2194,6 +2194,7 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_sdvo_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
index a828736..a4c0a04 100644 (file)
@@ -179,7 +179,7 @@ static void intel_update_primary_plane(struct intel_crtc *crtc)
 static void
 skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
                 struct drm_framebuffer *fb,
-                struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
+                int crtc_x, int crtc_y,
                 unsigned int crtc_w, unsigned int crtc_h,
                 uint32_t x, uint32_t y,
                 uint32_t src_w, uint32_t src_h)
@@ -187,23 +187,16 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
        struct drm_device *dev = drm_plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_plane *intel_plane = to_intel_plane(drm_plane);
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        const int pipe = intel_plane->pipe;
        const int plane = intel_plane->plane + 1;
        u32 plane_ctl, stride_div;
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey;
+       unsigned long surf_addr;
 
-       plane_ctl = I915_READ(PLANE_CTL(pipe, plane));
-
-       /* Mask out pixel format bits in case we change it */
-       plane_ctl &= ~PLANE_CTL_FORMAT_MASK;
-       plane_ctl &= ~PLANE_CTL_ORDER_RGBX;
-       plane_ctl &= ~PLANE_CTL_YUV422_ORDER_MASK;
-       plane_ctl &= ~PLANE_CTL_TILED_MASK;
-       plane_ctl &= ~PLANE_CTL_ALPHA_MASK;
-       plane_ctl &= ~PLANE_CTL_ROTATE_MASK;
-
-       /* Trickle feed has to be enabled */
-       plane_ctl &= ~PLANE_CTL_TRICKLE_FEED_DISABLE;
+       plane_ctl = PLANE_CTL_ENABLE |
+               PLANE_CTL_PIPE_CSC_ENABLE;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_RGB565:
@@ -264,9 +257,6 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
        if (drm_plane->state->rotation == BIT(DRM_ROTATE_180))
                plane_ctl |= PLANE_CTL_ROTATE_180;
 
-       plane_ctl |= PLANE_CTL_ENABLE;
-       plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE;
-
        intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h,
                                       pixel_size, true,
                                       src_w != crtc_w || src_h != crtc_h);
@@ -280,12 +270,25 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
        crtc_w--;
        crtc_h--;
 
+       if (key->flags) {
+               I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
+               I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
+               I915_WRITE(PLANE_KEYMSK(pipe, plane), key->channel_mask);
+       }
+
+       if (key->flags & I915_SET_COLORKEY_DESTINATION)
+               plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION;
+       else if (key->flags & I915_SET_COLORKEY_SOURCE)
+               plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
+
+       surf_addr = intel_plane_obj_offset(intel_plane, obj);
+
        I915_WRITE(PLANE_OFFSET(pipe, plane), (y << 16) | x);
        I915_WRITE(PLANE_STRIDE(pipe, plane), fb->pitches[0] / stride_div);
        I915_WRITE(PLANE_POS(pipe, plane), (crtc_y << 16) | crtc_x);
        I915_WRITE(PLANE_SIZE(pipe, plane), (crtc_h << 16) | crtc_w);
        I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
-       I915_WRITE(PLANE_SURF(pipe, plane), i915_gem_obj_ggtt_offset(obj));
+       I915_WRITE(PLANE_SURF(pipe, plane), surf_addr);
        POSTING_READ(PLANE_SURF(pipe, plane));
 }
 
@@ -298,73 +301,15 @@ skl_disable_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc)
        const int pipe = intel_plane->pipe;
        const int plane = intel_plane->plane + 1;
 
-       I915_WRITE(PLANE_CTL(pipe, plane),
-                  I915_READ(PLANE_CTL(pipe, plane)) & ~PLANE_CTL_ENABLE);
+       I915_WRITE(PLANE_CTL(pipe, plane), 0);
 
        /* Activate double buffered register update */
-       I915_WRITE(PLANE_CTL(pipe, plane), 0);
-       POSTING_READ(PLANE_CTL(pipe, plane));
+       I915_WRITE(PLANE_SURF(pipe, plane), 0);
+       POSTING_READ(PLANE_SURF(pipe, plane));
 
        intel_update_sprite_watermarks(drm_plane, crtc, 0, 0, 0, false, false);
 }
 
-static int
-skl_update_colorkey(struct drm_plane *drm_plane,
-                   struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = drm_plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane = to_intel_plane(drm_plane);
-       const int pipe = intel_plane->pipe;
-       const int plane = intel_plane->plane;
-       u32 plane_ctl;
-
-       I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
-       I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
-       I915_WRITE(PLANE_KEYMSK(pipe, plane), key->channel_mask);
-
-       plane_ctl = I915_READ(PLANE_CTL(pipe, plane));
-       plane_ctl &= ~PLANE_CTL_KEY_ENABLE_MASK;
-       if (key->flags & I915_SET_COLORKEY_DESTINATION)
-               plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION;
-       else if (key->flags & I915_SET_COLORKEY_SOURCE)
-               plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
-       I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
-
-       POSTING_READ(PLANE_CTL(pipe, plane));
-
-       return 0;
-}
-
-static void
-skl_get_colorkey(struct drm_plane *drm_plane,
-                struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = drm_plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane = to_intel_plane(drm_plane);
-       const int pipe = intel_plane->pipe;
-       const int plane = intel_plane->plane;
-       u32 plane_ctl;
-
-       key->min_value = I915_READ(PLANE_KEYVAL(pipe, plane));
-       key->max_value = I915_READ(PLANE_KEYMAX(pipe, plane));
-       key->channel_mask = I915_READ(PLANE_KEYMSK(pipe, plane));
-
-       plane_ctl = I915_READ(PLANE_CTL(pipe, plane));
-
-       switch (plane_ctl & PLANE_CTL_KEY_ENABLE_MASK) {
-       case PLANE_CTL_KEY_ENABLE_DESTINATION:
-               key->flags = I915_SET_COLORKEY_DESTINATION;
-               break;
-       case PLANE_CTL_KEY_ENABLE_SOURCE:
-               key->flags = I915_SET_COLORKEY_SOURCE;
-               break;
-       default:
-               key->flags = I915_SET_COLORKEY_NONE;
-       }
-}
-
 static void
 chv_update_csc(struct intel_plane *intel_plane, uint32_t format)
 {
@@ -407,7 +352,7 @@ chv_update_csc(struct intel_plane *intel_plane, uint32_t format)
 static void
 vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
                 struct drm_framebuffer *fb,
-                struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
+                int crtc_x, int crtc_y,
                 unsigned int crtc_w, unsigned int crtc_h,
                 uint32_t x, uint32_t y,
                 uint32_t src_w, uint32_t src_h)
@@ -416,19 +361,15 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_plane *intel_plane = to_intel_plane(dplane);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int pipe = intel_plane->pipe;
        int plane = intel_plane->plane;
        u32 sprctl;
        unsigned long sprsurf_offset, linear_offset;
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey;
 
-       sprctl = I915_READ(SPCNTR(pipe, plane));
-
-       /* Mask out pixel format bits in case we change it */
-       sprctl &= ~SP_PIXFORMAT_MASK;
-       sprctl &= ~SP_YUV_BYTE_ORDER_MASK;
-       sprctl &= ~SP_TILED;
-       sprctl &= ~SP_ROTATE_180;
+       sprctl = SP_ENABLE;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_YUYV:
@@ -482,8 +423,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
        if (obj->tiling_mode != I915_TILING_NONE)
                sprctl |= SP_TILED;
 
-       sprctl |= SP_ENABLE;
-
        intel_update_sprite_watermarks(dplane, crtc, src_w, src_h,
                                       pixel_size, true,
                                       src_w != crtc_w || src_h != crtc_h);
@@ -511,6 +450,15 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 
        intel_update_primary_plane(intel_crtc);
 
+       if (key->flags) {
+               I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value);
+               I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value);
+               I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask);
+       }
+
+       if (key->flags & I915_SET_COLORKEY_SOURCE)
+               sprctl |= SP_SOURCE_KEY;
+
        if (IS_CHERRYVIEW(dev) && pipe == PIPE_B)
                chv_update_csc(intel_plane, fb->pixel_format);
 
@@ -544,8 +492,8 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
 
        intel_update_primary_plane(intel_crtc);
 
-       I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) &
-                  ~SP_ENABLE);
+       I915_WRITE(SPCNTR(pipe, plane), 0);
+
        /* Activate double buffered register update */
        I915_WRITE(SPSURF(pipe, plane), 0);
 
@@ -554,61 +502,11 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
        intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false);
 }
 
-static int
-vlv_update_colorkey(struct drm_plane *dplane,
-                   struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = dplane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane = to_intel_plane(dplane);
-       int pipe = intel_plane->pipe;
-       int plane = intel_plane->plane;
-       u32 sprctl;
-
-       if (key->flags & I915_SET_COLORKEY_DESTINATION)
-               return -EINVAL;
-
-       I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value);
-       I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value);
-       I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask);
-
-       sprctl = I915_READ(SPCNTR(pipe, plane));
-       sprctl &= ~SP_SOURCE_KEY;
-       if (key->flags & I915_SET_COLORKEY_SOURCE)
-               sprctl |= SP_SOURCE_KEY;
-       I915_WRITE(SPCNTR(pipe, plane), sprctl);
-
-       POSTING_READ(SPKEYMSK(pipe, plane));
-
-       return 0;
-}
-
-static void
-vlv_get_colorkey(struct drm_plane *dplane,
-                struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = dplane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane = to_intel_plane(dplane);
-       int pipe = intel_plane->pipe;
-       int plane = intel_plane->plane;
-       u32 sprctl;
-
-       key->min_value = I915_READ(SPKEYMINVAL(pipe, plane));
-       key->max_value = I915_READ(SPKEYMAXVAL(pipe, plane));
-       key->channel_mask = I915_READ(SPKEYMSK(pipe, plane));
-
-       sprctl = I915_READ(SPCNTR(pipe, plane));
-       if (sprctl & SP_SOURCE_KEY)
-               key->flags = I915_SET_COLORKEY_SOURCE;
-       else
-               key->flags = I915_SET_COLORKEY_NONE;
-}
 
 static void
 ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                 struct drm_framebuffer *fb,
-                struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
+                int crtc_x, int crtc_y,
                 unsigned int crtc_w, unsigned int crtc_h,
                 uint32_t x, uint32_t y,
                 uint32_t src_w, uint32_t src_h)
@@ -617,19 +515,14 @@ ivb_update_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);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_plane->pipe;
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       enum pipe pipe = intel_plane->pipe;
        u32 sprctl, sprscale = 0;
        unsigned long sprsurf_offset, linear_offset;
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey;
 
-       sprctl = I915_READ(SPRCTL(pipe));
-
-       /* Mask out pixel format bits in case we change it */
-       sprctl &= ~SPRITE_PIXFORMAT_MASK;
-       sprctl &= ~SPRITE_RGB_ORDER_RGBX;
-       sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
-       sprctl &= ~SPRITE_TILED;
-       sprctl &= ~SPRITE_ROTATE_180;
+       sprctl = SPRITE_ENABLE;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_XBGR8888:
@@ -668,8 +561,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        else
                sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
 
-       sprctl |= SPRITE_ENABLE;
-
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                sprctl |= SPRITE_PIPE_CSC_ENABLE;
 
@@ -706,6 +597,17 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
        intel_update_primary_plane(intel_crtc);
 
+       if (key->flags) {
+               I915_WRITE(SPRKEYVAL(pipe), key->min_value);
+               I915_WRITE(SPRKEYMAX(pipe), key->max_value);
+               I915_WRITE(SPRKEYMSK(pipe), key->channel_mask);
+       }
+
+       if (key->flags & I915_SET_COLORKEY_DESTINATION)
+               sprctl |= SPRITE_DEST_KEY;
+       else if (key->flags & I915_SET_COLORKEY_SOURCE)
+               sprctl |= SPRITE_SOURCE_KEY;
+
        I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
 
@@ -747,73 +649,12 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
        I915_WRITE(SPRSURF(pipe), 0);
 
        intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
-       /*
-        * Avoid underruns when disabling the sprite.
-        * FIXME remove once watermark updates are done properly.
-        */
-       intel_crtc->atomic.wait_vblank = true;
-       intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
-}
-
-static int
-ivb_update_colorkey(struct drm_plane *plane,
-                   struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane;
-       u32 sprctl;
-       int ret = 0;
-
-       intel_plane = to_intel_plane(plane);
-
-       I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value);
-       I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value);
-       I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask);
-
-       sprctl = I915_READ(SPRCTL(intel_plane->pipe));
-       sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
-       if (key->flags & I915_SET_COLORKEY_DESTINATION)
-               sprctl |= SPRITE_DEST_KEY;
-       else if (key->flags & I915_SET_COLORKEY_SOURCE)
-               sprctl |= SPRITE_SOURCE_KEY;
-       I915_WRITE(SPRCTL(intel_plane->pipe), sprctl);
-
-       POSTING_READ(SPRKEYMSK(intel_plane->pipe));
-
-       return ret;
-}
-
-static void
-ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane;
-       u32 sprctl;
-
-       intel_plane = to_intel_plane(plane);
-
-       key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe));
-       key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe));
-       key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe));
-       key->flags = 0;
-
-       sprctl = I915_READ(SPRCTL(intel_plane->pipe));
-
-       if (sprctl & SPRITE_DEST_KEY)
-               key->flags = I915_SET_COLORKEY_DESTINATION;
-       else if (sprctl & SPRITE_SOURCE_KEY)
-               key->flags = I915_SET_COLORKEY_SOURCE;
-       else
-               key->flags = I915_SET_COLORKEY_NONE;
 }
 
 static void
 ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                 struct drm_framebuffer *fb,
-                struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
+                int crtc_x, int crtc_y,
                 unsigned int crtc_w, unsigned int crtc_h,
                 uint32_t x, uint32_t y,
                 uint32_t src_w, uint32_t src_h)
@@ -822,19 +663,14 @@ ilk_update_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);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int pipe = intel_plane->pipe;
        unsigned long dvssurf_offset, linear_offset;
        u32 dvscntr, dvsscale;
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey;
 
-       dvscntr = I915_READ(DVSCNTR(pipe));
-
-       /* Mask out pixel format bits in case we change it */
-       dvscntr &= ~DVS_PIXFORMAT_MASK;
-       dvscntr &= ~DVS_RGB_ORDER_XBGR;
-       dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
-       dvscntr &= ~DVS_TILED;
-       dvscntr &= ~DVS_ROTATE_180;
+       dvscntr = DVS_ENABLE;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_XBGR8888:
@@ -870,7 +706,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
        if (IS_GEN6(dev))
                dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
-       dvscntr |= DVS_ENABLE;
 
        intel_update_sprite_watermarks(plane, crtc, src_w, src_h,
                                       pixel_size, true,
@@ -902,6 +737,17 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
        intel_update_primary_plane(intel_crtc);
 
+       if (key->flags) {
+               I915_WRITE(DVSKEYVAL(pipe), key->min_value);
+               I915_WRITE(DVSKEYMAX(pipe), key->max_value);
+               I915_WRITE(DVSKEYMSK(pipe), key->channel_mask);
+       }
+
+       if (key->flags & I915_SET_COLORKEY_DESTINATION)
+               dvscntr |= DVS_DEST_KEY;
+       else if (key->flags & I915_SET_COLORKEY_SOURCE)
+               dvscntr |= DVS_SOURCE_KEY;
+
        I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
 
@@ -930,20 +776,14 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
 
        intel_update_primary_plane(intel_crtc);
 
-       I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
+       I915_WRITE(DVSCNTR(pipe), 0);
        /* Disable the scaler */
        I915_WRITE(DVSSCALE(pipe), 0);
+
        /* Flush double buffered register updates */
        I915_WRITE(DVSSURF(pipe), 0);
 
        intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
-       /*
-        * Avoid underruns when disabling the sprite.
-        * FIXME remove once watermark updates are done properly.
-        */
-       intel_crtc->atomic.wait_vblank = true;
-       intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
 }
 
 /**
@@ -1014,67 +854,9 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
        hsw_disable_ips(intel_crtc);
 }
 
-static int
-ilk_update_colorkey(struct drm_plane *plane,
-                   struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane;
-       u32 dvscntr;
-       int ret = 0;
-
-       intel_plane = to_intel_plane(plane);
-
-       I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value);
-       I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value);
-       I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask);
-
-       dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
-       dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
-       if (key->flags & I915_SET_COLORKEY_DESTINATION)
-               dvscntr |= DVS_DEST_KEY;
-       else if (key->flags & I915_SET_COLORKEY_SOURCE)
-               dvscntr |= DVS_SOURCE_KEY;
-       I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr);
-
-       POSTING_READ(DVSKEYMSK(intel_plane->pipe));
-
-       return ret;
-}
-
-static void
-ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane;
-       u32 dvscntr;
-
-       intel_plane = to_intel_plane(plane);
-
-       key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe));
-       key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe));
-       key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe));
-       key->flags = 0;
-
-       dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
-
-       if (dvscntr & DVS_DEST_KEY)
-               key->flags = I915_SET_COLORKEY_DESTINATION;
-       else if (dvscntr & DVS_SOURCE_KEY)
-               key->flags = I915_SET_COLORKEY_SOURCE;
-       else
-               key->flags = I915_SET_COLORKEY_NONE;
-}
-
 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;
+       return intel_plane->ckey.flags != I915_SET_COLORKEY_NONE;
 }
 
 static int
@@ -1257,11 +1039,18 @@ finish:
                if (!intel_crtc->primary_enabled && !state->hides_primary)
                        intel_crtc->atomic.post_enable_primary = true;
 
-               /* Update watermarks on tiling changes. */
-               if (!plane->state->fb || !state->base.fb ||
-                   plane->state->fb->modifier[0] !=
-                   state->base.fb->modifier[0])
+               if (intel_wm_need_update(plane, &state->base))
                        intel_crtc->atomic.update_wm = true;
+
+               if (!state->visible) {
+                       /*
+                        * Avoid underruns when disabling the sprite.
+                        * FIXME remove once watermark updates are done properly.
+                        */
+                       intel_crtc->atomic.wait_vblank = true;
+                       intel_crtc->atomic.update_sprite_watermarks |=
+                               (1 << drm_plane_index(plane));
+               }
        }
 
        return 0;
@@ -1275,7 +1064,6 @@ intel_commit_sprite_plane(struct drm_plane *plane,
        struct intel_crtc *intel_crtc;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *fb = state->base.fb;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int crtc_x, crtc_y;
        unsigned int crtc_w, crtc_h;
        uint32_t src_x, src_y, src_w, src_h;
@@ -1283,8 +1071,7 @@ intel_commit_sprite_plane(struct drm_plane *plane,
        crtc = crtc ? crtc : plane->crtc;
        intel_crtc = to_intel_crtc(crtc);
 
-       plane->fb = state->base.fb;
-       intel_plane->obj = obj;
+       plane->fb = fb;
 
        if (intel_crtc->active) {
                intel_crtc->primary_enabled = !state->hides_primary;
@@ -1298,7 +1085,7 @@ intel_commit_sprite_plane(struct drm_plane *plane,
                        src_y = state->src.y1;
                        src_w = drm_rect_width(&state->src);
                        src_h = drm_rect_height(&state->src);
-                       intel_plane->update_plane(plane, crtc, fb, obj,
+                       intel_plane->update_plane(plane, crtc, fb,
                                                  crtc_x, crtc_y, crtc_w, crtc_h,
                                                  src_x, src_y, src_w, src_h);
                } else {
@@ -1319,40 +1106,28 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
        if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
                return -EINVAL;
 
+       if (IS_VALLEYVIEW(dev) &&
+           set->flags & I915_SET_COLORKEY_DESTINATION)
+               return -EINVAL;
+
        drm_modeset_lock_all(dev);
 
        plane = drm_plane_find(dev, set->plane_id);
-       if (!plane) {
+       if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) {
                ret = -ENOENT;
                goto out_unlock;
        }
 
        intel_plane = to_intel_plane(plane);
-       ret = intel_plane->update_colorkey(plane, set);
-
-out_unlock:
-       drm_modeset_unlock_all(dev);
-       return ret;
-}
-
-int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
-                             struct drm_file *file_priv)
-{
-       struct drm_intel_sprite_colorkey *get = data;
-       struct drm_plane *plane;
-       struct intel_plane *intel_plane;
-       int ret = 0;
+       intel_plane->ckey = *set;
 
-       drm_modeset_lock_all(dev);
-
-       plane = drm_plane_find(dev, get->plane_id);
-       if (!plane) {
-               ret = -ENOENT;
-               goto out_unlock;
-       }
-
-       intel_plane = to_intel_plane(plane);
-       intel_plane->get_colorkey(plane, get);
+       /*
+        * The only way this could fail would be due to
+        * the current plane state being unsupportable already,
+        * and we dont't consider that an error for the
+        * colorkey ioctl. So just ignore any error.
+        */
+       intel_plane_restore(plane);
 
 out_unlock:
        drm_modeset_unlock_all(dev);
@@ -1445,8 +1220,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
                intel_plane->max_downscale = 16;
                intel_plane->update_plane = ilk_update_plane;
                intel_plane->disable_plane = ilk_disable_plane;
-               intel_plane->update_colorkey = ilk_update_colorkey;
-               intel_plane->get_colorkey = ilk_get_colorkey;
 
                if (IS_GEN6(dev)) {
                        plane_formats = snb_plane_formats;
@@ -1470,16 +1243,12 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
                if (IS_VALLEYVIEW(dev)) {
                        intel_plane->update_plane = vlv_update_plane;
                        intel_plane->disable_plane = vlv_disable_plane;
-                       intel_plane->update_colorkey = vlv_update_colorkey;
-                       intel_plane->get_colorkey = vlv_get_colorkey;
 
                        plane_formats = vlv_plane_formats;
                        num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
                } else {
                        intel_plane->update_plane = ivb_update_plane;
                        intel_plane->disable_plane = ivb_disable_plane;
-                       intel_plane->update_colorkey = ivb_update_colorkey;
-                       intel_plane->get_colorkey = ivb_get_colorkey;
 
                        plane_formats = snb_plane_formats;
                        num_plane_formats = ARRAY_SIZE(snb_plane_formats);
@@ -1494,8 +1263,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
                intel_plane->max_downscale = 1;
                intel_plane->update_plane = skl_update_plane;
                intel_plane->disable_plane = skl_disable_plane;
-               intel_plane->update_colorkey = skl_update_colorkey;
-               intel_plane->get_colorkey = skl_get_colorkey;
 
                plane_formats = skl_plane_formats;
                num_plane_formats = ARRAY_SIZE(skl_plane_formats);
index 892d23c..bc1d9d7 100644 (file)
@@ -1332,7 +1332,7 @@ intel_tv_detect(struct drm_connector *connector, bool force)
 
                if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) {
                        type = intel_tv_detect_type(intel_tv, connector);
-                       intel_release_load_detect_pipe(connector, &tmp);
+                       intel_release_load_detect_pipe(connector, &tmp, &ctx);
                        status = type < 0 ?
                                connector_status_disconnected :
                                connector_status_connected;
@@ -1516,6 +1516,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
index c6f2c47..74f505b 100644 (file)
@@ -431,15 +431,6 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
 
-static struct device_node *imx_drm_of_get_next_endpoint(
-               const struct device_node *parent, struct device_node *prev)
-{
-       struct device_node *node = of_graph_get_next_endpoint(parent, prev);
-
-       of_node_put(prev);
-       return node;
-}
-
 /*
  * @node: device tree node containing encoder input ports
  * @encoder: drm_encoder
@@ -448,7 +439,7 @@ int imx_drm_encoder_get_mux_id(struct device_node *node,
                               struct drm_encoder *encoder)
 {
        struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
-       struct device_node *ep = NULL;
+       struct device_node *ep;
        struct of_endpoint endpoint;
        struct device_node *port;
        int ret;
@@ -456,18 +447,15 @@ int imx_drm_encoder_get_mux_id(struct device_node *node,
        if (!node || !imx_crtc)
                return -EINVAL;
 
-       do {
-               ep = imx_drm_of_get_next_endpoint(node, ep);
-               if (!ep)
-                       break;
-
+       for_each_endpoint_of_node(node, ep) {
                port = of_graph_get_remote_port(ep);
                of_node_put(port);
                if (port == imx_crtc->crtc->port) {
                        ret = of_graph_parse_endpoint(ep, &endpoint);
+                       of_node_put(ep);
                        return ret ? ret : endpoint.port;
                }
-       } while (ep);
+       }
 
        return -EINVAL;
 }
index bacbbb7..0a6f676 100644 (file)
@@ -35,3 +35,14 @@ config DRM_MSM_REGISTER_LOGGING
          Compile in support for logging register reads/writes in a format
          that can be parsed by envytools demsm tool.  If enabled, register
          logging can be switched on via msm.reglog=y module param.
+
+config DRM_MSM_DSI
+       bool "Enable DSI support in MSM DRM driver"
+       depends on DRM_MSM
+       select DRM_PANEL
+       select DRM_MIPI_DSI
+       default y
+       help
+         Choose this option if you have a need for MIPI DSI connector
+         support.
+
index 674a132..ab20867 100644 (file)
@@ -50,5 +50,10 @@ msm-y := \
 
 msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o
 msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
+msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
+                       dsi/dsi_host.o \
+                       dsi/dsi_manager.o \
+                       dsi/dsi_phy.o \
+                       mdp/mdp5/mdp5_cmd_encoder.o
 
 obj-$(CONFIG_DRM_MSM)  += msm.o
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
new file mode 100644 (file)
index 0000000..28d1f95
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "dsi.h"
+
+struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
+{
+       if (!msm_dsi || !msm_dsi->panel)
+               return NULL;
+
+       return (msm_dsi->panel_flags & MIPI_DSI_MODE_VIDEO) ?
+               msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID] :
+               msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID];
+}
+
+static void dsi_destroy(struct msm_dsi *msm_dsi)
+{
+       if (!msm_dsi)
+               return;
+
+       msm_dsi_manager_unregister(msm_dsi);
+       if (msm_dsi->host) {
+               msm_dsi_host_destroy(msm_dsi->host);
+               msm_dsi->host = NULL;
+       }
+
+       platform_set_drvdata(msm_dsi->pdev, NULL);
+}
+
+static struct msm_dsi *dsi_init(struct platform_device *pdev)
+{
+       struct msm_dsi *msm_dsi = NULL;
+       int ret;
+
+       if (!pdev) {
+               dev_err(&pdev->dev, "no dsi device\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL);
+       if (!msm_dsi) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+       DBG("dsi probed=%p", msm_dsi);
+
+       msm_dsi->pdev = pdev;
+       platform_set_drvdata(pdev, msm_dsi);
+
+       /* Init dsi host */
+       ret = msm_dsi_host_init(msm_dsi);
+       if (ret)
+               goto fail;
+
+       /* Register to dsi manager */
+       ret = msm_dsi_manager_register(msm_dsi);
+       if (ret)
+               goto fail;
+
+       return msm_dsi;
+
+fail:
+       if (msm_dsi)
+               dsi_destroy(msm_dsi);
+
+       return ERR_PTR(ret);
+}
+
+static int dsi_bind(struct device *dev, struct device *master, void *data)
+{
+       struct drm_device *drm = dev_get_drvdata(master);
+       struct msm_drm_private *priv = drm->dev_private;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct msm_dsi *msm_dsi;
+
+       DBG("");
+       msm_dsi = dsi_init(pdev);
+       if (IS_ERR(msm_dsi))
+               return PTR_ERR(msm_dsi);
+
+       priv->dsi[msm_dsi->id] = msm_dsi;
+
+       return 0;
+}
+
+static void dsi_unbind(struct device *dev, struct device *master,
+               void *data)
+{
+       struct drm_device *drm = dev_get_drvdata(master);
+       struct msm_drm_private *priv = drm->dev_private;
+       struct msm_dsi *msm_dsi = dev_get_drvdata(dev);
+       int id = msm_dsi->id;
+
+       if (priv->dsi[id]) {
+               dsi_destroy(msm_dsi);
+               priv->dsi[id] = NULL;
+       }
+}
+
+static const struct component_ops dsi_ops = {
+       .bind   = dsi_bind,
+       .unbind = dsi_unbind,
+};
+
+static int dsi_dev_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &dsi_ops);
+}
+
+static int dsi_dev_remove(struct platform_device *pdev)
+{
+       DBG("");
+       component_del(&pdev->dev, &dsi_ops);
+       return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+       { .compatible = "qcom,mdss-dsi-ctrl" },
+       {}
+};
+
+static struct platform_driver dsi_driver = {
+       .probe = dsi_dev_probe,
+       .remove = dsi_dev_remove,
+       .driver = {
+               .name = "msm_dsi",
+               .of_match_table = dt_match,
+       },
+};
+
+void __init msm_dsi_register(void)
+{
+       DBG("");
+       platform_driver_register(&dsi_driver);
+}
+
+void __exit msm_dsi_unregister(void)
+{
+       DBG("");
+       platform_driver_unregister(&dsi_driver);
+}
+
+int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
+               struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       int ret, i;
+
+       if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] ||
+               !encoders[MSM_DSI_CMD_ENCODER_ID]))
+               return -EINVAL;
+
+       msm_dsi->dev = dev;
+
+       ret = msm_dsi_host_modeset_init(msm_dsi->host, dev);
+       if (ret) {
+               dev_err(dev->dev, "failed to modeset init host: %d\n", ret);
+               goto fail;
+       }
+
+       msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
+       if (IS_ERR(msm_dsi->bridge)) {
+               ret = PTR_ERR(msm_dsi->bridge);
+               dev_err(dev->dev, "failed to create dsi bridge: %d\n", ret);
+               msm_dsi->bridge = NULL;
+               goto fail;
+       }
+
+       msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id);
+       if (IS_ERR(msm_dsi->connector)) {
+               ret = PTR_ERR(msm_dsi->connector);
+               dev_err(dev->dev, "failed to create dsi connector: %d\n", ret);
+               msm_dsi->connector = NULL;
+               goto fail;
+       }
+
+       for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
+               encoders[i]->bridge = msm_dsi->bridge;
+               msm_dsi->encoders[i] = encoders[i];
+       }
+
+       priv->bridges[priv->num_bridges++]       = msm_dsi->bridge;
+       priv->connectors[priv->num_connectors++] = msm_dsi->connector;
+
+       return 0;
+fail:
+       if (msm_dsi) {
+               /* bridge/connector are normally destroyed by drm: */
+               if (msm_dsi->bridge) {
+                       msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
+                       msm_dsi->bridge = NULL;
+               }
+               if (msm_dsi->connector) {
+                       msm_dsi->connector->funcs->destroy(msm_dsi->connector);
+                       msm_dsi->connector = NULL;
+               }
+       }
+
+       return ret;
+}
+
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
new file mode 100644 (file)
index 0000000..10f54d4
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DSI_CONNECTOR_H__
+#define __DSI_CONNECTOR_H__
+
+#include <linux/platform_device.h>
+
+#include "drm_crtc.h"
+#include "drm_mipi_dsi.h"
+#include "drm_panel.h"
+
+#include "msm_drv.h"
+
+#define DSI_0  0
+#define DSI_1  1
+#define DSI_MAX        2
+
+#define DSI_CLOCK_MASTER       DSI_0
+#define DSI_CLOCK_SLAVE                DSI_1
+
+#define DSI_LEFT               DSI_0
+#define DSI_RIGHT              DSI_1
+
+/* According to the current drm framework sequence, take the encoder of
+ * DSI_1 as master encoder
+ */
+#define DSI_ENCODER_MASTER     DSI_1
+#define DSI_ENCODER_SLAVE      DSI_0
+
+struct msm_dsi {
+       struct drm_device *dev;
+       struct platform_device *pdev;
+
+       struct drm_connector *connector;
+       struct drm_bridge *bridge;
+
+       struct mipi_dsi_host *host;
+       struct msm_dsi_phy *phy;
+       struct drm_panel *panel;
+       unsigned long panel_flags;
+       bool phy_enabled;
+
+       /* the encoders we are hooked to (outside of dsi block) */
+       struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM];
+
+       int id;
+};
+
+/* dsi manager */
+struct drm_bridge *msm_dsi_manager_bridge_init(u8 id);
+void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge);
+struct drm_connector *msm_dsi_manager_connector_init(u8 id);
+int msm_dsi_manager_phy_enable(int id,
+               const unsigned long bit_rate, const unsigned long esc_rate,
+               u32 *clk_pre, u32 *clk_post);
+void msm_dsi_manager_phy_disable(int id);
+int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
+bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len);
+int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
+void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
+
+/* msm dsi */
+struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
+
+/* dsi host */
+int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
+                                       const struct mipi_dsi_msg *msg);
+void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host,
+                                       const struct mipi_dsi_msg *msg);
+int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host,
+                                       const struct mipi_dsi_msg *msg);
+int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
+                                       const struct mipi_dsi_msg *msg);
+void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host,
+                                       u32 iova, u32 len);
+int msm_dsi_host_enable(struct mipi_dsi_host *host);
+int msm_dsi_host_disable(struct mipi_dsi_host *host);
+int msm_dsi_host_power_on(struct mipi_dsi_host *host);
+int msm_dsi_host_power_off(struct mipi_dsi_host *host);
+int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
+                                       struct drm_display_mode *mode);
+struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
+                                       unsigned long *panel_flags);
+int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer);
+void msm_dsi_host_unregister(struct mipi_dsi_host *host);
+void msm_dsi_host_destroy(struct mipi_dsi_host *host);
+int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
+                                       struct drm_device *dev);
+int msm_dsi_host_init(struct msm_dsi *msm_dsi);
+
+/* dsi phy */
+struct msm_dsi_phy;
+enum msm_dsi_phy_type {
+       MSM_DSI_PHY_UNKNOWN,
+       MSM_DSI_PHY_28NM,
+       MSM_DSI_PHY_MAX
+};
+struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
+                       enum msm_dsi_phy_type type, int id);
+int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
+       const unsigned long bit_rate, const unsigned long esc_rate);
+int msm_dsi_phy_disable(struct msm_dsi_phy *phy);
+void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
+                                       u32 *clk_pre, u32 *clk_post);
+#endif /* __DSI_CONNECTOR_H__ */
+
index abf1bba..1dcfae2 100644 (file)
@@ -8,19 +8,10 @@ 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                 (    676 bytes, from 2014-12-05 15:34:49)
-- /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            (  20908 bytes, from 2014-12-08 16:13:00)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
-- /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         (   1686 bytes, from 2014-10-31 16:48:57)
-- /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           (  26848 bytes, from 2015-01-13 23:55:57)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
-
-Copyright (C) 2013 by the following authors:
+- /usr2/hali/local/envytools/envytools/rnndb/dsi/dsi.xml             (  18681 bytes, from 2015-03-04 23:08:31)
+- /usr2/hali/local/envytools/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-01-28 21:43:22)
+
+Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
 
 Permission is hereby granted, free of charge, to any person obtaining
@@ -51,11 +42,11 @@ enum dsi_traffic_mode {
        BURST_MODE = 2,
 };
 
-enum dsi_dst_format {
-       DST_FORMAT_RGB565 = 0,
-       DST_FORMAT_RGB666 = 1,
-       DST_FORMAT_RGB666_LOOSE = 2,
-       DST_FORMAT_RGB888 = 3,
+enum dsi_vid_dst_format {
+       VID_DST_FORMAT_RGB565 = 0,
+       VID_DST_FORMAT_RGB666 = 1,
+       VID_DST_FORMAT_RGB666_LOOSE = 2,
+       VID_DST_FORMAT_RGB888 = 3,
 };
 
 enum dsi_rgb_swap {
@@ -69,20 +60,63 @@ enum dsi_rgb_swap {
 
 enum dsi_cmd_trigger {
        TRIGGER_NONE = 0,
+       TRIGGER_SEOF = 1,
        TRIGGER_TE = 2,
        TRIGGER_SW = 4,
        TRIGGER_SW_SEOF = 5,
        TRIGGER_SW_TE = 6,
 };
 
+enum dsi_cmd_dst_format {
+       CMD_DST_FORMAT_RGB111 = 0,
+       CMD_DST_FORMAT_RGB332 = 3,
+       CMD_DST_FORMAT_RGB444 = 4,
+       CMD_DST_FORMAT_RGB565 = 6,
+       CMD_DST_FORMAT_RGB666 = 7,
+       CMD_DST_FORMAT_RGB888 = 8,
+};
+
+enum dsi_lane_swap {
+       LANE_SWAP_0123 = 0,
+       LANE_SWAP_3012 = 1,
+       LANE_SWAP_2301 = 2,
+       LANE_SWAP_1230 = 3,
+       LANE_SWAP_0321 = 4,
+       LANE_SWAP_1032 = 5,
+       LANE_SWAP_2103 = 6,
+       LANE_SWAP_3210 = 7,
+};
+
 #define DSI_IRQ_CMD_DMA_DONE                                   0x00000001
 #define DSI_IRQ_MASK_CMD_DMA_DONE                              0x00000002
 #define DSI_IRQ_CMD_MDP_DONE                                   0x00000100
 #define DSI_IRQ_MASK_CMD_MDP_DONE                              0x00000200
 #define DSI_IRQ_VIDEO_DONE                                     0x00010000
 #define DSI_IRQ_MASK_VIDEO_DONE                                        0x00020000
+#define DSI_IRQ_BTA_DONE                                       0x00100000
+#define DSI_IRQ_MASK_BTA_DONE                                  0x00200000
 #define DSI_IRQ_ERROR                                          0x01000000
 #define DSI_IRQ_MASK_ERROR                                     0x02000000
+#define REG_DSI_6G_HW_VERSION                                  0x00000000
+#define DSI_6G_HW_VERSION_MAJOR__MASK                          0xf0000000
+#define DSI_6G_HW_VERSION_MAJOR__SHIFT                         28
+static inline uint32_t DSI_6G_HW_VERSION_MAJOR(uint32_t val)
+{
+       return ((val) << DSI_6G_HW_VERSION_MAJOR__SHIFT) & DSI_6G_HW_VERSION_MAJOR__MASK;
+}
+#define DSI_6G_HW_VERSION_MINOR__MASK                          0x0fff0000
+#define DSI_6G_HW_VERSION_MINOR__SHIFT                         16
+static inline uint32_t DSI_6G_HW_VERSION_MINOR(uint32_t val)
+{
+       return ((val) << DSI_6G_HW_VERSION_MINOR__SHIFT) & DSI_6G_HW_VERSION_MINOR__MASK;
+}
+#define DSI_6G_HW_VERSION_STEP__MASK                           0x0000ffff
+#define DSI_6G_HW_VERSION_STEP__SHIFT                          0
+static inline uint32_t DSI_6G_HW_VERSION_STEP(uint32_t val)
+{
+       return ((val) << DSI_6G_HW_VERSION_STEP__SHIFT) & DSI_6G_HW_VERSION_STEP__MASK;
+}
+
 #define REG_DSI_CTRL                                           0x00000000
 #define DSI_CTRL_ENABLE                                                0x00000001
 #define DSI_CTRL_VID_MODE_EN                                   0x00000002
@@ -96,11 +130,15 @@ enum dsi_cmd_trigger {
 #define DSI_CTRL_CRC_CHECK                                     0x01000000
 
 #define REG_DSI_STATUS0                                                0x00000004
+#define DSI_STATUS0_CMD_MODE_ENGINE_BUSY                       0x00000001
 #define DSI_STATUS0_CMD_MODE_DMA_BUSY                          0x00000002
+#define DSI_STATUS0_CMD_MODE_MDP_BUSY                          0x00000004
 #define DSI_STATUS0_VIDEO_MODE_ENGINE_BUSY                     0x00000008
 #define DSI_STATUS0_DSI_BUSY                                   0x00000010
+#define DSI_STATUS0_INTERLEAVE_OP_CONTENTION                   0x80000000
 
 #define REG_DSI_FIFO_STATUS                                    0x00000008
+#define DSI_FIFO_STATUS_CMD_MDP_FIFO_UNDERFLOW                 0x00000080
 
 #define REG_DSI_VID_CFG0                                       0x0000000c
 #define DSI_VID_CFG0_VIRT_CHANNEL__MASK                                0x00000003
@@ -111,7 +149,7 @@ static inline uint32_t DSI_VID_CFG0_VIRT_CHANNEL(uint32_t val)
 }
 #define DSI_VID_CFG0_DST_FORMAT__MASK                          0x00000030
 #define DSI_VID_CFG0_DST_FORMAT__SHIFT                         4
-static inline uint32_t DSI_VID_CFG0_DST_FORMAT(enum dsi_dst_format val)
+static inline uint32_t DSI_VID_CFG0_DST_FORMAT(enum dsi_vid_dst_format val)
 {
        return ((val) << DSI_VID_CFG0_DST_FORMAT__SHIFT) & DSI_VID_CFG0_DST_FORMAT__MASK;
 }
@@ -129,21 +167,15 @@ static inline uint32_t DSI_VID_CFG0_TRAFFIC_MODE(enum dsi_traffic_mode val)
 #define DSI_VID_CFG0_PULSE_MODE_HSA_HE                         0x10000000
 
 #define REG_DSI_VID_CFG1                                       0x0000001c
-#define DSI_VID_CFG1_R_SEL                                     0x00000010
-#define DSI_VID_CFG1_G_SEL                                     0x00000100
-#define DSI_VID_CFG1_B_SEL                                     0x00001000
-#define DSI_VID_CFG1_RGB_SWAP__MASK                            0x00070000
-#define DSI_VID_CFG1_RGB_SWAP__SHIFT                           16
+#define DSI_VID_CFG1_R_SEL                                     0x00000001
+#define DSI_VID_CFG1_G_SEL                                     0x00000010
+#define DSI_VID_CFG1_B_SEL                                     0x00000100
+#define DSI_VID_CFG1_RGB_SWAP__MASK                            0x00007000
+#define DSI_VID_CFG1_RGB_SWAP__SHIFT                           12
 static inline uint32_t DSI_VID_CFG1_RGB_SWAP(enum dsi_rgb_swap val)
 {
        return ((val) << DSI_VID_CFG1_RGB_SWAP__SHIFT) & DSI_VID_CFG1_RGB_SWAP__MASK;
 }
-#define DSI_VID_CFG1_INTERLEAVE_MAX__MASK                      0x00f00000
-#define DSI_VID_CFG1_INTERLEAVE_MAX__SHIFT                     20
-static inline uint32_t DSI_VID_CFG1_INTERLEAVE_MAX(uint32_t val)
-{
-       return ((val) << DSI_VID_CFG1_INTERLEAVE_MAX__SHIFT) & DSI_VID_CFG1_INTERLEAVE_MAX__MASK;
-}
 
 #define REG_DSI_ACTIVE_H                                       0x00000020
 #define DSI_ACTIVE_H_START__MASK                               0x00000fff
@@ -201,32 +233,115 @@ static inline uint32_t DSI_ACTIVE_HSYNC_END(uint32_t val)
        return ((val) << DSI_ACTIVE_HSYNC_END__SHIFT) & DSI_ACTIVE_HSYNC_END__MASK;
 }
 
-#define REG_DSI_ACTIVE_VSYNC                                   0x00000034
-#define DSI_ACTIVE_VSYNC_START__MASK                           0x00000fff
-#define DSI_ACTIVE_VSYNC_START__SHIFT                          0
-static inline uint32_t DSI_ACTIVE_VSYNC_START(uint32_t val)
+#define REG_DSI_ACTIVE_VSYNC_HPOS                              0x00000030
+#define DSI_ACTIVE_VSYNC_HPOS_START__MASK                      0x00000fff
+#define DSI_ACTIVE_VSYNC_HPOS_START__SHIFT                     0
+static inline uint32_t DSI_ACTIVE_VSYNC_HPOS_START(uint32_t val)
 {
-       return ((val) << DSI_ACTIVE_VSYNC_START__SHIFT) & DSI_ACTIVE_VSYNC_START__MASK;
+       return ((val) << DSI_ACTIVE_VSYNC_HPOS_START__SHIFT) & DSI_ACTIVE_VSYNC_HPOS_START__MASK;
 }
-#define DSI_ACTIVE_VSYNC_END__MASK                             0x0fff0000
-#define DSI_ACTIVE_VSYNC_END__SHIFT                            16
-static inline uint32_t DSI_ACTIVE_VSYNC_END(uint32_t val)
+#define DSI_ACTIVE_VSYNC_HPOS_END__MASK                                0x0fff0000
+#define DSI_ACTIVE_VSYNC_HPOS_END__SHIFT                       16
+static inline uint32_t DSI_ACTIVE_VSYNC_HPOS_END(uint32_t val)
 {
-       return ((val) << DSI_ACTIVE_VSYNC_END__SHIFT) & DSI_ACTIVE_VSYNC_END__MASK;
+       return ((val) << DSI_ACTIVE_VSYNC_HPOS_END__SHIFT) & DSI_ACTIVE_VSYNC_HPOS_END__MASK;
+}
+
+#define REG_DSI_ACTIVE_VSYNC_VPOS                              0x00000034
+#define DSI_ACTIVE_VSYNC_VPOS_START__MASK                      0x00000fff
+#define DSI_ACTIVE_VSYNC_VPOS_START__SHIFT                     0
+static inline uint32_t DSI_ACTIVE_VSYNC_VPOS_START(uint32_t val)
+{
+       return ((val) << DSI_ACTIVE_VSYNC_VPOS_START__SHIFT) & DSI_ACTIVE_VSYNC_VPOS_START__MASK;
+}
+#define DSI_ACTIVE_VSYNC_VPOS_END__MASK                                0x0fff0000
+#define DSI_ACTIVE_VSYNC_VPOS_END__SHIFT                       16
+static inline uint32_t DSI_ACTIVE_VSYNC_VPOS_END(uint32_t val)
+{
+       return ((val) << DSI_ACTIVE_VSYNC_VPOS_END__SHIFT) & DSI_ACTIVE_VSYNC_VPOS_END__MASK;
 }
 
 #define REG_DSI_CMD_DMA_CTRL                                   0x00000038
+#define DSI_CMD_DMA_CTRL_BROADCAST_EN                          0x80000000
 #define DSI_CMD_DMA_CTRL_FROM_FRAME_BUFFER                     0x10000000
 #define DSI_CMD_DMA_CTRL_LOW_POWER                             0x04000000
 
 #define REG_DSI_CMD_CFG0                                       0x0000003c
+#define DSI_CMD_CFG0_DST_FORMAT__MASK                          0x0000000f
+#define DSI_CMD_CFG0_DST_FORMAT__SHIFT                         0
+static inline uint32_t DSI_CMD_CFG0_DST_FORMAT(enum dsi_cmd_dst_format val)
+{
+       return ((val) << DSI_CMD_CFG0_DST_FORMAT__SHIFT) & DSI_CMD_CFG0_DST_FORMAT__MASK;
+}
+#define DSI_CMD_CFG0_R_SEL                                     0x00000010
+#define DSI_CMD_CFG0_G_SEL                                     0x00000100
+#define DSI_CMD_CFG0_B_SEL                                     0x00001000
+#define DSI_CMD_CFG0_INTERLEAVE_MAX__MASK                      0x00f00000
+#define DSI_CMD_CFG0_INTERLEAVE_MAX__SHIFT                     20
+static inline uint32_t DSI_CMD_CFG0_INTERLEAVE_MAX(uint32_t val)
+{
+       return ((val) << DSI_CMD_CFG0_INTERLEAVE_MAX__SHIFT) & DSI_CMD_CFG0_INTERLEAVE_MAX__MASK;
+}
+#define DSI_CMD_CFG0_RGB_SWAP__MASK                            0x00070000
+#define DSI_CMD_CFG0_RGB_SWAP__SHIFT                           16
+static inline uint32_t DSI_CMD_CFG0_RGB_SWAP(enum dsi_rgb_swap val)
+{
+       return ((val) << DSI_CMD_CFG0_RGB_SWAP__SHIFT) & DSI_CMD_CFG0_RGB_SWAP__MASK;
+}
 
 #define REG_DSI_CMD_CFG1                                       0x00000040
+#define DSI_CMD_CFG1_WR_MEM_START__MASK                                0x000000ff
+#define DSI_CMD_CFG1_WR_MEM_START__SHIFT                       0
+static inline uint32_t DSI_CMD_CFG1_WR_MEM_START(uint32_t val)
+{
+       return ((val) << DSI_CMD_CFG1_WR_MEM_START__SHIFT) & DSI_CMD_CFG1_WR_MEM_START__MASK;
+}
+#define DSI_CMD_CFG1_WR_MEM_CONTINUE__MASK                     0x0000ff00
+#define DSI_CMD_CFG1_WR_MEM_CONTINUE__SHIFT                    8
+static inline uint32_t DSI_CMD_CFG1_WR_MEM_CONTINUE(uint32_t val)
+{
+       return ((val) << DSI_CMD_CFG1_WR_MEM_CONTINUE__SHIFT) & DSI_CMD_CFG1_WR_MEM_CONTINUE__MASK;
+}
+#define DSI_CMD_CFG1_INSERT_DCS_COMMAND                                0x00010000
 
 #define REG_DSI_DMA_BASE                                       0x00000044
 
 #define REG_DSI_DMA_LEN                                                0x00000048
 
+#define REG_DSI_CMD_MDP_STREAM_CTRL                            0x00000054
+#define DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__MASK                        0x0000003f
+#define DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__SHIFT               0
+static inline uint32_t DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE(uint32_t val)
+{
+       return ((val) << DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__SHIFT) & DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__MASK;
+}
+#define DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__MASK          0x00000300
+#define DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__SHIFT         8
+static inline uint32_t DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL(uint32_t val)
+{
+       return ((val) << DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__SHIFT) & DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__MASK;
+}
+#define DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__MASK               0xffff0000
+#define DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__SHIFT              16
+static inline uint32_t DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT(uint32_t val)
+{
+       return ((val) << DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__SHIFT) & DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__MASK;
+}
+
+#define REG_DSI_CMD_MDP_STREAM_TOTAL                           0x00000058
+#define DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__MASK                 0x00000fff
+#define DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__SHIFT                        0
+static inline uint32_t DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL(uint32_t val)
+{
+       return ((val) << DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__SHIFT) & DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__MASK;
+}
+#define DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__MASK                 0x0fff0000
+#define DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__SHIFT                        16
+static inline uint32_t DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL(uint32_t val)
+{
+       return ((val) << DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__SHIFT) & DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__MASK;
+}
+
 #define REG_DSI_ACK_ERR_STATUS                                 0x00000064
 
 static inline uint32_t REG_DSI_RDBK(uint32_t i0) { return 0x00000068 + 0x4*i0; }
@@ -234,19 +349,25 @@ static inline uint32_t REG_DSI_RDBK(uint32_t i0) { return 0x00000068 + 0x4*i0; }
 static inline uint32_t REG_DSI_RDBK_DATA(uint32_t i0) { return 0x00000068 + 0x4*i0; }
 
 #define REG_DSI_TRIG_CTRL                                      0x00000080
-#define DSI_TRIG_CTRL_DMA_TRIGGER__MASK                                0x0000000f
+#define DSI_TRIG_CTRL_DMA_TRIGGER__MASK                                0x00000007
 #define DSI_TRIG_CTRL_DMA_TRIGGER__SHIFT                       0
 static inline uint32_t DSI_TRIG_CTRL_DMA_TRIGGER(enum dsi_cmd_trigger val)
 {
        return ((val) << DSI_TRIG_CTRL_DMA_TRIGGER__SHIFT) & DSI_TRIG_CTRL_DMA_TRIGGER__MASK;
 }
-#define DSI_TRIG_CTRL_MDP_TRIGGER__MASK                                0x000000f0
+#define DSI_TRIG_CTRL_MDP_TRIGGER__MASK                                0x00000070
 #define DSI_TRIG_CTRL_MDP_TRIGGER__SHIFT                       4
 static inline uint32_t DSI_TRIG_CTRL_MDP_TRIGGER(enum dsi_cmd_trigger val)
 {
        return ((val) << DSI_TRIG_CTRL_MDP_TRIGGER__SHIFT) & DSI_TRIG_CTRL_MDP_TRIGGER__MASK;
 }
-#define DSI_TRIG_CTRL_STREAM                                   0x00000100
+#define DSI_TRIG_CTRL_STREAM__MASK                             0x00000300
+#define DSI_TRIG_CTRL_STREAM__SHIFT                            8
+static inline uint32_t DSI_TRIG_CTRL_STREAM(uint32_t val)
+{
+       return ((val) << DSI_TRIG_CTRL_STREAM__SHIFT) & DSI_TRIG_CTRL_STREAM__MASK;
+}
+#define DSI_TRIG_CTRL_BLOCK_DMA_WITHIN_FRAME                   0x00001000
 #define DSI_TRIG_CTRL_TE                                       0x80000000
 
 #define REG_DSI_TRIG_DMA                                       0x0000008c
@@ -274,6 +395,12 @@ static inline uint32_t DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(uint32_t val)
 #define DSI_EOT_PACKET_CTRL_RX_EOT_IGNORE                      0x00000010
 
 #define REG_DSI_LANE_SWAP_CTRL                                 0x000000ac
+#define DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__MASK                  0x00000007
+#define DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__SHIFT                 0
+static inline uint32_t DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(enum dsi_lane_swap val)
+{
+       return ((val) << DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__SHIFT) & DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__MASK;
+}
 
 #define REG_DSI_ERR_INT_MASK0                                  0x00000108
 
@@ -282,8 +409,36 @@ static inline uint32_t DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(uint32_t val)
 #define REG_DSI_RESET                                          0x00000114
 
 #define REG_DSI_CLK_CTRL                                       0x00000118
+#define DSI_CLK_CTRL_AHBS_HCLK_ON                              0x00000001
+#define DSI_CLK_CTRL_AHBM_SCLK_ON                              0x00000002
+#define DSI_CLK_CTRL_PCLK_ON                                   0x00000004
+#define DSI_CLK_CTRL_DSICLK_ON                                 0x00000008
+#define DSI_CLK_CTRL_BYTECLK_ON                                        0x00000010
+#define DSI_CLK_CTRL_ESCCLK_ON                                 0x00000020
+#define DSI_CLK_CTRL_FORCE_ON_DYN_AHBM_HCLK                    0x00000200
+
+#define REG_DSI_CLK_STATUS                                     0x0000011c
+#define DSI_CLK_STATUS_PLL_UNLOCKED                            0x00010000
 
 #define REG_DSI_PHY_RESET                                      0x00000128
+#define DSI_PHY_RESET_RESET                                    0x00000001
+
+#define REG_DSI_RDBK_DATA_CTRL                                 0x000001d0
+#define DSI_RDBK_DATA_CTRL_COUNT__MASK                         0x00ff0000
+#define DSI_RDBK_DATA_CTRL_COUNT__SHIFT                                16
+static inline uint32_t DSI_RDBK_DATA_CTRL_COUNT(uint32_t val)
+{
+       return ((val) << DSI_RDBK_DATA_CTRL_COUNT__SHIFT) & DSI_RDBK_DATA_CTRL_COUNT__MASK;
+}
+#define DSI_RDBK_DATA_CTRL_CLR                                 0x00000001
+
+#define REG_DSI_VERSION                                                0x000001f0
+#define DSI_VERSION_MAJOR__MASK                                        0xff000000
+#define DSI_VERSION_MAJOR__SHIFT                               24
+static inline uint32_t DSI_VERSION_MAJOR(uint32_t val)
+{
+       return ((val) << DSI_VERSION_MAJOR__SHIFT) & DSI_VERSION_MAJOR__MASK;
+}
 
 #define REG_DSI_PHY_PLL_CTRL_0                                 0x00000200
 #define DSI_PHY_PLL_CTRL_0_ENABLE                              0x00000001
@@ -501,5 +656,184 @@ static inline uint32_t REG_DSI_8960_LN_TEST_STR_1(uint32_t i0) { return 0x000003
 #define REG_DSI_8960_PHY_CAL_STATUS                            0x00000550
 #define DSI_8960_PHY_CAL_STATUS_CAL_BUSY                       0x00000010
 
+static inline uint32_t REG_DSI_28nm_PHY_LN(uint32_t i0) { return 0x00000000 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_0(uint32_t i0) { return 0x00000000 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_1(uint32_t i0) { return 0x00000004 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_2(uint32_t i0) { return 0x00000008 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_3(uint32_t i0) { return 0x0000000c + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_4(uint32_t i0) { return 0x00000010 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_TEST_DATAPATH(uint32_t i0) { return 0x00000014 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_DEBUG_SEL(uint32_t i0) { return 0x00000018 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_TEST_STR_0(uint32_t i0) { return 0x0000001c + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_TEST_STR_1(uint32_t i0) { return 0x00000020 + 0x40*i0; }
+
+#define REG_DSI_28nm_PHY_LNCK_CFG_0                            0x00000100
+
+#define REG_DSI_28nm_PHY_LNCK_CFG_1                            0x00000104
+
+#define REG_DSI_28nm_PHY_LNCK_CFG_2                            0x00000108
+
+#define REG_DSI_28nm_PHY_LNCK_CFG_3                            0x0000010c
+
+#define REG_DSI_28nm_PHY_LNCK_CFG_4                            0x00000110
+
+#define REG_DSI_28nm_PHY_LNCK_TEST_DATAPATH                    0x00000114
+
+#define REG_DSI_28nm_PHY_LNCK_DEBUG_SEL                                0x00000118
+
+#define REG_DSI_28nm_PHY_LNCK_TEST_STR0                                0x0000011c
+
+#define REG_DSI_28nm_PHY_LNCK_TEST_STR1                                0x00000120
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_0                         0x00000140
+#define DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__MASK              0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT             0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_1                         0x00000144
+#define DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK             0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT            0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_2                         0x00000148
+#define DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK           0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT          0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_3                         0x0000014c
+#define DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8                  0x00000001
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_4                         0x00000150
+#define DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__MASK               0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT              0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_5                         0x00000154
+#define DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__MASK               0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT              0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_6                         0x00000158
+#define DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__MASK            0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT           0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_7                         0x0000015c
+#define DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__MASK              0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT             0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_8                         0x00000160
+#define DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__MASK               0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__SHIFT              0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_9                         0x00000164
+#define DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__MASK                 0x00000007
+#define DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__SHIFT                        0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__MASK;
+}
+#define DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__MASK               0x00000070
+#define DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__SHIFT              4
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_10                                0x00000168
+#define DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__MASK               0x00000007
+#define DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__SHIFT              0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_11                                0x0000016c
+#define DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK            0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT           0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK;
+}
+
+#define REG_DSI_28nm_PHY_CTRL_0                                        0x00000170
+
+#define REG_DSI_28nm_PHY_CTRL_1                                        0x00000174
+
+#define REG_DSI_28nm_PHY_CTRL_2                                        0x00000178
+
+#define REG_DSI_28nm_PHY_CTRL_3                                        0x0000017c
+
+#define REG_DSI_28nm_PHY_CTRL_4                                        0x00000180
+
+#define REG_DSI_28nm_PHY_STRENGTH_0                            0x00000184
+
+#define REG_DSI_28nm_PHY_STRENGTH_1                            0x00000188
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_0                           0x000001b4
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_1                           0x000001b8
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_2                           0x000001bc
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_3                           0x000001c0
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_4                           0x000001c4
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_5                           0x000001c8
+
+#define REG_DSI_28nm_PHY_GLBL_TEST_CTRL                                0x000001d4
+
+#define REG_DSI_28nm_PHY_LDO_CNTRL                             0x000001dc
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_0                      0x00000000
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_1                      0x00000004
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_2                      0x00000008
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_3                      0x0000000c
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_4                      0x00000010
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_5                      0x00000014
+
+#define REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG                 0x00000018
+
 
 #endif /* DSI_XML */
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
new file mode 100644 (file)
index 0000000..fdc54e3
--- /dev/null
@@ -0,0 +1,1993 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <video/mipi_display.h>
+
+#include "dsi.h"
+#include "dsi.xml.h"
+
+#define MSM_DSI_VER_MAJOR_V2   0x02
+#define MSM_DSI_VER_MAJOR_6G   0x03
+#define MSM_DSI_6G_VER_MINOR_V1_0      0x10000000
+#define MSM_DSI_6G_VER_MINOR_V1_1      0x10010000
+#define MSM_DSI_6G_VER_MINOR_V1_1_1    0x10010001
+#define MSM_DSI_6G_VER_MINOR_V1_2      0x10020000
+#define MSM_DSI_6G_VER_MINOR_V1_3_1    0x10030001
+
+#define DSI_6G_REG_SHIFT       4
+
+#define DSI_REGULATOR_MAX      8
+struct dsi_reg_entry {
+       char name[32];
+       int min_voltage;
+       int max_voltage;
+       int enable_load;
+       int disable_load;
+};
+
+struct dsi_reg_config {
+       int num;
+       struct dsi_reg_entry regs[DSI_REGULATOR_MAX];
+};
+
+struct dsi_config {
+       u32 major;
+       u32 minor;
+       u32 io_offset;
+       enum msm_dsi_phy_type phy_type;
+       struct dsi_reg_config reg_cfg;
+};
+
+static const struct dsi_config dsi_cfgs[] = {
+       {MSM_DSI_VER_MAJOR_V2, 0, 0, MSM_DSI_PHY_UNKNOWN},
+       { /* 8974 v1 */
+               .major = MSM_DSI_VER_MAJOR_6G,
+               .minor = MSM_DSI_6G_VER_MINOR_V1_0,
+               .io_offset = DSI_6G_REG_SHIFT,
+               .phy_type = MSM_DSI_PHY_28NM,
+               .reg_cfg = {
+                       .num = 4,
+                       .regs = {
+                               {"gdsc", -1, -1, -1, -1},
+                               {"vdd", 3000000, 3000000, 150000, 100},
+                               {"vdda", 1200000, 1200000, 100000, 100},
+                               {"vddio", 1800000, 1800000, 100000, 100},
+                       },
+               },
+       },
+       { /* 8974 v2 */
+               .major = MSM_DSI_VER_MAJOR_6G,
+               .minor = MSM_DSI_6G_VER_MINOR_V1_1,
+               .io_offset = DSI_6G_REG_SHIFT,
+               .phy_type = MSM_DSI_PHY_28NM,
+               .reg_cfg = {
+                       .num = 4,
+                       .regs = {
+                               {"gdsc", -1, -1, -1, -1},
+                               {"vdd", 3000000, 3000000, 150000, 100},
+                               {"vdda", 1200000, 1200000, 100000, 100},
+                               {"vddio", 1800000, 1800000, 100000, 100},
+                       },
+               },
+       },
+       { /* 8974 v3 */
+               .major = MSM_DSI_VER_MAJOR_6G,
+               .minor = MSM_DSI_6G_VER_MINOR_V1_1_1,
+               .io_offset = DSI_6G_REG_SHIFT,
+               .phy_type = MSM_DSI_PHY_28NM,
+               .reg_cfg = {
+                       .num = 4,
+                       .regs = {
+                               {"gdsc", -1, -1, -1, -1},
+                               {"vdd", 3000000, 3000000, 150000, 100},
+                               {"vdda", 1200000, 1200000, 100000, 100},
+                               {"vddio", 1800000, 1800000, 100000, 100},
+                       },
+               },
+       },
+       { /* 8084 */
+               .major = MSM_DSI_VER_MAJOR_6G,
+               .minor = MSM_DSI_6G_VER_MINOR_V1_2,
+               .io_offset = DSI_6G_REG_SHIFT,
+               .phy_type = MSM_DSI_PHY_28NM,
+               .reg_cfg = {
+                       .num = 4,
+                       .regs = {
+                               {"gdsc", -1, -1, -1, -1},
+                               {"vdd", 3000000, 3000000, 150000, 100},
+                               {"vdda", 1200000, 1200000, 100000, 100},
+                               {"vddio", 1800000, 1800000, 100000, 100},
+                       },
+               },
+       },
+       { /* 8916 */
+               .major = MSM_DSI_VER_MAJOR_6G,
+               .minor = MSM_DSI_6G_VER_MINOR_V1_3_1,
+               .io_offset = DSI_6G_REG_SHIFT,
+               .phy_type = MSM_DSI_PHY_28NM,
+               .reg_cfg = {
+                       .num = 4,
+                       .regs = {
+                               {"gdsc", -1, -1, -1, -1},
+                               {"vdd", 2850000, 2850000, 100000, 100},
+                               {"vdda", 1200000, 1200000, 100000, 100},
+                               {"vddio", 1800000, 1800000, 100000, 100},
+                       },
+               },
+       },
+};
+
+static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
+{
+       u32 ver;
+       u32 ver_6g;
+
+       if (!major || !minor)
+               return -EINVAL;
+
+       /* From DSI6G(v3), addition of a 6G_HW_VERSION register at offset 0
+        * makes all other registers 4-byte shifted down.
+        */
+       ver_6g = msm_readl(base + REG_DSI_6G_HW_VERSION);
+       if (ver_6g == 0) {
+               ver = msm_readl(base + REG_DSI_VERSION);
+               ver = FIELD(ver, DSI_VERSION_MAJOR);
+               if (ver <= MSM_DSI_VER_MAJOR_V2) {
+                       /* old versions */
+                       *major = ver;
+                       *minor = 0;
+                       return 0;
+               } else {
+                       return -EINVAL;
+               }
+       } else {
+               ver = msm_readl(base + DSI_6G_REG_SHIFT + REG_DSI_VERSION);
+               ver = FIELD(ver, DSI_VERSION_MAJOR);
+               if (ver == MSM_DSI_VER_MAJOR_6G) {
+                       /* 6G version */
+                       *major = ver;
+                       *minor = ver_6g;
+                       return 0;
+               } else {
+                       return -EINVAL;
+               }
+       }
+}
+
+#define DSI_ERR_STATE_ACK                      0x0000
+#define DSI_ERR_STATE_TIMEOUT                  0x0001
+#define DSI_ERR_STATE_DLN0_PHY                 0x0002
+#define DSI_ERR_STATE_FIFO                     0x0004
+#define DSI_ERR_STATE_MDP_FIFO_UNDERFLOW       0x0008
+#define DSI_ERR_STATE_INTERLEAVE_OP_CONTENTION 0x0010
+#define DSI_ERR_STATE_PLL_UNLOCKED             0x0020
+
+#define DSI_CLK_CTRL_ENABLE_CLKS       \
+               (DSI_CLK_CTRL_AHBS_HCLK_ON | DSI_CLK_CTRL_AHBM_SCLK_ON | \
+               DSI_CLK_CTRL_PCLK_ON | DSI_CLK_CTRL_DSICLK_ON | \
+               DSI_CLK_CTRL_BYTECLK_ON | DSI_CLK_CTRL_ESCCLK_ON | \
+               DSI_CLK_CTRL_FORCE_ON_DYN_AHBM_HCLK)
+
+struct msm_dsi_host {
+       struct mipi_dsi_host base;
+
+       struct platform_device *pdev;
+       struct drm_device *dev;
+
+       int id;
+
+       void __iomem *ctrl_base;
+       struct regulator_bulk_data supplies[DSI_REGULATOR_MAX];
+       struct clk *mdp_core_clk;
+       struct clk *ahb_clk;
+       struct clk *axi_clk;
+       struct clk *mmss_misc_ahb_clk;
+       struct clk *byte_clk;
+       struct clk *esc_clk;
+       struct clk *pixel_clk;
+       u32 byte_clk_rate;
+
+       struct gpio_desc *disp_en_gpio;
+       struct gpio_desc *te_gpio;
+
+       const struct dsi_config *cfg;
+
+       struct completion dma_comp;
+       struct completion video_comp;
+       struct mutex dev_mutex;
+       struct mutex cmd_mutex;
+       struct mutex clk_mutex;
+       spinlock_t intr_lock; /* Protect interrupt ctrl register */
+
+       u32 err_work_state;
+       struct work_struct err_work;
+       struct workqueue_struct *workqueue;
+
+       struct drm_gem_object *tx_gem_obj;
+       u8 *rx_buf;
+
+       struct drm_display_mode *mode;
+
+       /* Panel info */
+       struct device_node *panel_node;
+       unsigned int channel;
+       unsigned int lanes;
+       enum mipi_dsi_pixel_format format;
+       unsigned long mode_flags;
+
+       u32 dma_cmd_ctrl_restore;
+
+       bool registered;
+       bool power_on;
+       int irq;
+};
+
+static u32 dsi_get_bpp(const enum mipi_dsi_pixel_format fmt)
+{
+       switch (fmt) {
+       case MIPI_DSI_FMT_RGB565:               return 16;
+       case MIPI_DSI_FMT_RGB666_PACKED:        return 18;
+       case MIPI_DSI_FMT_RGB666:
+       case MIPI_DSI_FMT_RGB888:
+       default:                                return 24;
+       }
+}
+
+static inline u32 dsi_read(struct msm_dsi_host *msm_host, u32 reg)
+{
+       return msm_readl(msm_host->ctrl_base + msm_host->cfg->io_offset + reg);
+}
+static inline void dsi_write(struct msm_dsi_host *msm_host, u32 reg, u32 data)
+{
+       msm_writel(data, msm_host->ctrl_base + msm_host->cfg->io_offset + reg);
+}
+
+static int dsi_host_regulator_enable(struct msm_dsi_host *msm_host);
+static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host);
+
+static const struct dsi_config *dsi_get_config(struct msm_dsi_host *msm_host)
+{
+       const struct dsi_config *cfg;
+       struct regulator *gdsc_reg;
+       int i, ret;
+       u32 major = 0, minor = 0;
+
+       gdsc_reg = regulator_get(&msm_host->pdev->dev, "gdsc");
+       if (IS_ERR_OR_NULL(gdsc_reg)) {
+               pr_err("%s: cannot get gdsc\n", __func__);
+               goto fail;
+       }
+       ret = regulator_enable(gdsc_reg);
+       if (ret) {
+               pr_err("%s: unable to enable gdsc\n", __func__);
+               regulator_put(gdsc_reg);
+               goto fail;
+       }
+       ret = clk_prepare_enable(msm_host->ahb_clk);
+       if (ret) {
+               pr_err("%s: unable to enable ahb_clk\n", __func__);
+               regulator_disable(gdsc_reg);
+               regulator_put(gdsc_reg);
+               goto fail;
+       }
+
+       ret = dsi_get_version(msm_host->ctrl_base, &major, &minor);
+
+       clk_disable_unprepare(msm_host->ahb_clk);
+       regulator_disable(gdsc_reg);
+       regulator_put(gdsc_reg);
+       if (ret) {
+               pr_err("%s: Invalid version\n", __func__);
+               goto fail;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(dsi_cfgs); i++) {
+               cfg = dsi_cfgs + i;
+               if ((cfg->major == major) && (cfg->minor == minor))
+                       return cfg;
+       }
+       pr_err("%s: Version %x:%x not support\n", __func__, major, minor);
+
+fail:
+       return NULL;
+}
+
+static inline struct msm_dsi_host *to_msm_dsi_host(struct mipi_dsi_host *host)
+{
+       return container_of(host, struct msm_dsi_host, base);
+}
+
+static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host)
+{
+       struct regulator_bulk_data *s = msm_host->supplies;
+       const struct dsi_reg_entry *regs = msm_host->cfg->reg_cfg.regs;
+       int num = msm_host->cfg->reg_cfg.num;
+       int i;
+
+       DBG("");
+       for (i = num - 1; i >= 0; i--)
+               if (regs[i].disable_load >= 0)
+                       regulator_set_optimum_mode(s[i].consumer,
+                                               regs[i].disable_load);
+
+       regulator_bulk_disable(num, s);
+}
+
+static int dsi_host_regulator_enable(struct msm_dsi_host *msm_host)
+{
+       struct regulator_bulk_data *s = msm_host->supplies;
+       const struct dsi_reg_entry *regs = msm_host->cfg->reg_cfg.regs;
+       int num = msm_host->cfg->reg_cfg.num;
+       int ret, i;
+
+       DBG("");
+       for (i = 0; i < num; i++) {
+               if (regs[i].enable_load >= 0) {
+                       ret = regulator_set_optimum_mode(s[i].consumer,
+                                                       regs[i].enable_load);
+                       if (ret < 0) {
+                               pr_err("regulator %d set op mode failed, %d\n",
+                                       i, ret);
+                               goto fail;
+                       }
+               }
+       }
+
+       ret = regulator_bulk_enable(num, s);
+       if (ret < 0) {
+               pr_err("regulator enable failed, %d\n", ret);
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       for (i--; i >= 0; i--)
+               regulator_set_optimum_mode(s[i].consumer, regs[i].disable_load);
+       return ret;
+}
+
+static int dsi_regulator_init(struct msm_dsi_host *msm_host)
+{
+       struct regulator_bulk_data *s = msm_host->supplies;
+       const struct dsi_reg_entry *regs = msm_host->cfg->reg_cfg.regs;
+       int num = msm_host->cfg->reg_cfg.num;
+       int i, ret;
+
+       for (i = 0; i < num; i++)
+               s[i].supply = regs[i].name;
+
+       ret = devm_regulator_bulk_get(&msm_host->pdev->dev, num, s);
+       if (ret < 0) {
+               pr_err("%s: failed to init regulator, ret=%d\n",
+                                               __func__, ret);
+               return ret;
+       }
+
+       for (i = 0; i < num; i++) {
+               if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) {
+                       ret = regulator_set_voltage(s[i].consumer,
+                               regs[i].min_voltage, regs[i].max_voltage);
+                       if (ret < 0) {
+                               pr_err("regulator %d set voltage failed, %d\n",
+                                       i, ret);
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int dsi_clk_init(struct msm_dsi_host *msm_host)
+{
+       struct device *dev = &msm_host->pdev->dev;
+       int ret = 0;
+
+       msm_host->mdp_core_clk = devm_clk_get(dev, "mdp_core_clk");
+       if (IS_ERR(msm_host->mdp_core_clk)) {
+               ret = PTR_ERR(msm_host->mdp_core_clk);
+               pr_err("%s: Unable to get mdp core clk. ret=%d\n",
+                       __func__, ret);
+               goto exit;
+       }
+
+       msm_host->ahb_clk = devm_clk_get(dev, "iface_clk");
+       if (IS_ERR(msm_host->ahb_clk)) {
+               ret = PTR_ERR(msm_host->ahb_clk);
+               pr_err("%s: Unable to get mdss ahb clk. ret=%d\n",
+                       __func__, ret);
+               goto exit;
+       }
+
+       msm_host->axi_clk = devm_clk_get(dev, "bus_clk");
+       if (IS_ERR(msm_host->axi_clk)) {
+               ret = PTR_ERR(msm_host->axi_clk);
+               pr_err("%s: Unable to get axi bus clk. ret=%d\n",
+                       __func__, ret);
+               goto exit;
+       }
+
+       msm_host->mmss_misc_ahb_clk = devm_clk_get(dev, "core_mmss_clk");
+       if (IS_ERR(msm_host->mmss_misc_ahb_clk)) {
+               ret = PTR_ERR(msm_host->mmss_misc_ahb_clk);
+               pr_err("%s: Unable to get mmss misc ahb clk. ret=%d\n",
+                       __func__, ret);
+               goto exit;
+       }
+
+       msm_host->byte_clk = devm_clk_get(dev, "byte_clk");
+       if (IS_ERR(msm_host->byte_clk)) {
+               ret = PTR_ERR(msm_host->byte_clk);
+               pr_err("%s: can't find dsi_byte_clk. ret=%d\n",
+                       __func__, ret);
+               msm_host->byte_clk = NULL;
+               goto exit;
+       }
+
+       msm_host->pixel_clk = devm_clk_get(dev, "pixel_clk");
+       if (IS_ERR(msm_host->pixel_clk)) {
+               ret = PTR_ERR(msm_host->pixel_clk);
+               pr_err("%s: can't find dsi_pixel_clk. ret=%d\n",
+                       __func__, ret);
+               msm_host->pixel_clk = NULL;
+               goto exit;
+       }
+
+       msm_host->esc_clk = devm_clk_get(dev, "core_clk");
+       if (IS_ERR(msm_host->esc_clk)) {
+               ret = PTR_ERR(msm_host->esc_clk);
+               pr_err("%s: can't find dsi_esc_clk. ret=%d\n",
+                       __func__, ret);
+               msm_host->esc_clk = NULL;
+               goto exit;
+       }
+
+exit:
+       return ret;
+}
+
+static int dsi_bus_clk_enable(struct msm_dsi_host *msm_host)
+{
+       int ret;
+
+       DBG("id=%d", msm_host->id);
+
+       ret = clk_prepare_enable(msm_host->mdp_core_clk);
+       if (ret) {
+               pr_err("%s: failed to enable mdp_core_clock, %d\n",
+                                                        __func__, ret);
+               goto core_clk_err;
+       }
+
+       ret = clk_prepare_enable(msm_host->ahb_clk);
+       if (ret) {
+               pr_err("%s: failed to enable ahb clock, %d\n", __func__, ret);
+               goto ahb_clk_err;
+       }
+
+       ret = clk_prepare_enable(msm_host->axi_clk);
+       if (ret) {
+               pr_err("%s: failed to enable ahb clock, %d\n", __func__, ret);
+               goto axi_clk_err;
+       }
+
+       ret = clk_prepare_enable(msm_host->mmss_misc_ahb_clk);
+       if (ret) {
+               pr_err("%s: failed to enable mmss misc ahb clk, %d\n",
+                       __func__, ret);
+               goto misc_ahb_clk_err;
+       }
+
+       return 0;
+
+misc_ahb_clk_err:
+       clk_disable_unprepare(msm_host->axi_clk);
+axi_clk_err:
+       clk_disable_unprepare(msm_host->ahb_clk);
+ahb_clk_err:
+       clk_disable_unprepare(msm_host->mdp_core_clk);
+core_clk_err:
+       return ret;
+}
+
+static void dsi_bus_clk_disable(struct msm_dsi_host *msm_host)
+{
+       DBG("");
+       clk_disable_unprepare(msm_host->mmss_misc_ahb_clk);
+       clk_disable_unprepare(msm_host->axi_clk);
+       clk_disable_unprepare(msm_host->ahb_clk);
+       clk_disable_unprepare(msm_host->mdp_core_clk);
+}
+
+static int dsi_link_clk_enable(struct msm_dsi_host *msm_host)
+{
+       int ret;
+
+       DBG("Set clk rates: pclk=%d, byteclk=%d",
+               msm_host->mode->clock, msm_host->byte_clk_rate);
+
+       ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate);
+       if (ret) {
+               pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret);
+               goto error;
+       }
+
+       ret = clk_set_rate(msm_host->pixel_clk, msm_host->mode->clock * 1000);
+       if (ret) {
+               pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret);
+               goto error;
+       }
+
+       ret = clk_prepare_enable(msm_host->esc_clk);
+       if (ret) {
+               pr_err("%s: Failed to enable dsi esc clk\n", __func__);
+               goto error;
+       }
+
+       ret = clk_prepare_enable(msm_host->byte_clk);
+       if (ret) {
+               pr_err("%s: Failed to enable dsi byte clk\n", __func__);
+               goto byte_clk_err;
+       }
+
+       ret = clk_prepare_enable(msm_host->pixel_clk);
+       if (ret) {
+               pr_err("%s: Failed to enable dsi pixel clk\n", __func__);
+               goto pixel_clk_err;
+       }
+
+       return 0;
+
+pixel_clk_err:
+       clk_disable_unprepare(msm_host->byte_clk);
+byte_clk_err:
+       clk_disable_unprepare(msm_host->esc_clk);
+error:
+       return ret;
+}
+
+static void dsi_link_clk_disable(struct msm_dsi_host *msm_host)
+{
+       clk_disable_unprepare(msm_host->esc_clk);
+       clk_disable_unprepare(msm_host->pixel_clk);
+       clk_disable_unprepare(msm_host->byte_clk);
+}
+
+static int dsi_clk_ctrl(struct msm_dsi_host *msm_host, bool enable)
+{
+       int ret = 0;
+
+       mutex_lock(&msm_host->clk_mutex);
+       if (enable) {
+               ret = dsi_bus_clk_enable(msm_host);
+               if (ret) {
+                       pr_err("%s: Can not enable bus clk, %d\n",
+                               __func__, ret);
+                       goto unlock_ret;
+               }
+               ret = dsi_link_clk_enable(msm_host);
+               if (ret) {
+                       pr_err("%s: Can not enable link clk, %d\n",
+                               __func__, ret);
+                       dsi_bus_clk_disable(msm_host);
+                       goto unlock_ret;
+               }
+       } else {
+               dsi_link_clk_disable(msm_host);
+               dsi_bus_clk_disable(msm_host);
+       }
+
+unlock_ret:
+       mutex_unlock(&msm_host->clk_mutex);
+       return ret;
+}
+
+static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host)
+{
+       struct drm_display_mode *mode = msm_host->mode;
+       u8 lanes = msm_host->lanes;
+       u32 bpp = dsi_get_bpp(msm_host->format);
+       u32 pclk_rate;
+
+       if (!mode) {
+               pr_err("%s: mode not set\n", __func__);
+               return -EINVAL;
+       }
+
+       pclk_rate = mode->clock * 1000;
+       if (lanes > 0) {
+               msm_host->byte_clk_rate = (pclk_rate * bpp) / (8 * lanes);
+       } else {
+               pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
+               msm_host->byte_clk_rate = (pclk_rate * bpp) / 8;
+       }
+
+       DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate);
+
+       return 0;
+}
+
+static void dsi_phy_sw_reset(struct msm_dsi_host *msm_host)
+{
+       DBG("");
+       dsi_write(msm_host, REG_DSI_PHY_RESET, DSI_PHY_RESET_RESET);
+       /* Make sure fully reset */
+       wmb();
+       udelay(1000);
+       dsi_write(msm_host, REG_DSI_PHY_RESET, 0);
+       udelay(100);
+}
+
+static void dsi_intr_ctrl(struct msm_dsi_host *msm_host, u32 mask, int enable)
+{
+       u32 intr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&msm_host->intr_lock, flags);
+       intr = dsi_read(msm_host, REG_DSI_INTR_CTRL);
+
+       if (enable)
+               intr |= mask;
+       else
+               intr &= ~mask;
+
+       DBG("intr=%x enable=%d", intr, enable);
+
+       dsi_write(msm_host, REG_DSI_INTR_CTRL, intr);
+       spin_unlock_irqrestore(&msm_host->intr_lock, flags);
+}
+
+static inline enum dsi_traffic_mode dsi_get_traffic_mode(const u32 mode_flags)
+{
+       if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+               return BURST_MODE;
+       else if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+               return NON_BURST_SYNCH_PULSE;
+
+       return NON_BURST_SYNCH_EVENT;
+}
+
+static inline enum dsi_vid_dst_format dsi_get_vid_fmt(
+                               const enum mipi_dsi_pixel_format mipi_fmt)
+{
+       switch (mipi_fmt) {
+       case MIPI_DSI_FMT_RGB888:       return VID_DST_FORMAT_RGB888;
+       case MIPI_DSI_FMT_RGB666:       return VID_DST_FORMAT_RGB666_LOOSE;
+       case MIPI_DSI_FMT_RGB666_PACKED:        return VID_DST_FORMAT_RGB666;
+       case MIPI_DSI_FMT_RGB565:       return VID_DST_FORMAT_RGB565;
+       default:                        return VID_DST_FORMAT_RGB888;
+       }
+}
+
+static inline enum dsi_cmd_dst_format dsi_get_cmd_fmt(
+                               const enum mipi_dsi_pixel_format mipi_fmt)
+{
+       switch (mipi_fmt) {
+       case MIPI_DSI_FMT_RGB888:       return CMD_DST_FORMAT_RGB888;
+       case MIPI_DSI_FMT_RGB666_PACKED:
+       case MIPI_DSI_FMT_RGB666:       return VID_DST_FORMAT_RGB666;
+       case MIPI_DSI_FMT_RGB565:       return CMD_DST_FORMAT_RGB565;
+       default:                        return CMD_DST_FORMAT_RGB888;
+       }
+}
+
+static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable,
+                               u32 clk_pre, u32 clk_post)
+{
+       u32 flags = msm_host->mode_flags;
+       enum mipi_dsi_pixel_format mipi_fmt = msm_host->format;
+       u32 data = 0;
+
+       if (!enable) {
+               dsi_write(msm_host, REG_DSI_CTRL, 0);
+               return;
+       }
+
+       if (flags & MIPI_DSI_MODE_VIDEO) {
+               if (flags & MIPI_DSI_MODE_VIDEO_HSE)
+                       data |= DSI_VID_CFG0_PULSE_MODE_HSA_HE;
+               if (flags & MIPI_DSI_MODE_VIDEO_HFP)
+                       data |= DSI_VID_CFG0_HFP_POWER_STOP;
+               if (flags & MIPI_DSI_MODE_VIDEO_HBP)
+                       data |= DSI_VID_CFG0_HBP_POWER_STOP;
+               if (flags & MIPI_DSI_MODE_VIDEO_HSA)
+                       data |= DSI_VID_CFG0_HSA_POWER_STOP;
+               /* Always set low power stop mode for BLLP
+                * to let command engine send packets
+                */
+               data |= DSI_VID_CFG0_EOF_BLLP_POWER_STOP |
+                       DSI_VID_CFG0_BLLP_POWER_STOP;
+               data |= DSI_VID_CFG0_TRAFFIC_MODE(dsi_get_traffic_mode(flags));
+               data |= DSI_VID_CFG0_DST_FORMAT(dsi_get_vid_fmt(mipi_fmt));
+               data |= DSI_VID_CFG0_VIRT_CHANNEL(msm_host->channel);
+               dsi_write(msm_host, REG_DSI_VID_CFG0, data);
+
+               /* Do not swap RGB colors */
+               data = DSI_VID_CFG1_RGB_SWAP(SWAP_RGB);
+               dsi_write(msm_host, REG_DSI_VID_CFG1, 0);
+       } else {
+               /* Do not swap RGB colors */
+               data = DSI_CMD_CFG0_RGB_SWAP(SWAP_RGB);
+               data |= DSI_CMD_CFG0_DST_FORMAT(dsi_get_cmd_fmt(mipi_fmt));
+               dsi_write(msm_host, REG_DSI_CMD_CFG0, data);
+
+               data = DSI_CMD_CFG1_WR_MEM_START(MIPI_DCS_WRITE_MEMORY_START) |
+                       DSI_CMD_CFG1_WR_MEM_CONTINUE(
+                                       MIPI_DCS_WRITE_MEMORY_CONTINUE);
+               /* Always insert DCS command */
+               data |= DSI_CMD_CFG1_INSERT_DCS_COMMAND;
+               dsi_write(msm_host, REG_DSI_CMD_CFG1, data);
+       }
+
+       dsi_write(msm_host, REG_DSI_CMD_DMA_CTRL,
+                       DSI_CMD_DMA_CTRL_FROM_FRAME_BUFFER |
+                       DSI_CMD_DMA_CTRL_LOW_POWER);
+
+       data = 0;
+       /* Always assume dedicated TE pin */
+       data |= DSI_TRIG_CTRL_TE;
+       data |= DSI_TRIG_CTRL_MDP_TRIGGER(TRIGGER_NONE);
+       data |= DSI_TRIG_CTRL_DMA_TRIGGER(TRIGGER_SW);
+       data |= DSI_TRIG_CTRL_STREAM(msm_host->channel);
+       if ((msm_host->cfg->major == MSM_DSI_VER_MAJOR_6G) &&
+               (msm_host->cfg->minor >= MSM_DSI_6G_VER_MINOR_V1_2))
+               data |= DSI_TRIG_CTRL_BLOCK_DMA_WITHIN_FRAME;
+       dsi_write(msm_host, REG_DSI_TRIG_CTRL, data);
+
+       data = DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(clk_post) |
+               DSI_CLKOUT_TIMING_CTRL_T_CLK_PRE(clk_pre);
+       dsi_write(msm_host, REG_DSI_CLKOUT_TIMING_CTRL, data);
+
+       data = 0;
+       if (!(flags & MIPI_DSI_MODE_EOT_PACKET))
+               data |= DSI_EOT_PACKET_CTRL_TX_EOT_APPEND;
+       dsi_write(msm_host, REG_DSI_EOT_PACKET_CTRL, data);
+
+       /* allow only ack-err-status to generate interrupt */
+       dsi_write(msm_host, REG_DSI_ERR_INT_MASK0, 0x13ff3fe0);
+
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, 1);
+
+       dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS);
+
+       data = DSI_CTRL_CLK_EN;
+
+       DBG("lane number=%d", msm_host->lanes);
+       if (msm_host->lanes == 2) {
+               data |= DSI_CTRL_LANE1 | DSI_CTRL_LANE2;
+               /* swap lanes for 2-lane panel for better performance */
+               dsi_write(msm_host, REG_DSI_LANE_SWAP_CTRL,
+                       DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(LANE_SWAP_1230));
+       } else {
+               /* Take 4 lanes as default */
+               data |= DSI_CTRL_LANE0 | DSI_CTRL_LANE1 | DSI_CTRL_LANE2 |
+                       DSI_CTRL_LANE3;
+               /* Do not swap lanes for 4-lane panel */
+               dsi_write(msm_host, REG_DSI_LANE_SWAP_CTRL,
+                       DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(LANE_SWAP_0123));
+       }
+       data |= DSI_CTRL_ENABLE;
+
+       dsi_write(msm_host, REG_DSI_CTRL, data);
+}
+
+static void dsi_timing_setup(struct msm_dsi_host *msm_host)
+{
+       struct drm_display_mode *mode = msm_host->mode;
+       u32 hs_start = 0, vs_start = 0; /* take sync start as 0 */
+       u32 h_total = mode->htotal;
+       u32 v_total = mode->vtotal;
+       u32 hs_end = mode->hsync_end - mode->hsync_start;
+       u32 vs_end = mode->vsync_end - mode->vsync_start;
+       u32 ha_start = h_total - mode->hsync_start;
+       u32 ha_end = ha_start + mode->hdisplay;
+       u32 va_start = v_total - mode->vsync_start;
+       u32 va_end = va_start + mode->vdisplay;
+       u32 wc;
+
+       DBG("");
+
+       if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) {
+               dsi_write(msm_host, REG_DSI_ACTIVE_H,
+                       DSI_ACTIVE_H_START(ha_start) |
+                       DSI_ACTIVE_H_END(ha_end));
+               dsi_write(msm_host, REG_DSI_ACTIVE_V,
+                       DSI_ACTIVE_V_START(va_start) |
+                       DSI_ACTIVE_V_END(va_end));
+               dsi_write(msm_host, REG_DSI_TOTAL,
+                       DSI_TOTAL_H_TOTAL(h_total - 1) |
+                       DSI_TOTAL_V_TOTAL(v_total - 1));
+
+               dsi_write(msm_host, REG_DSI_ACTIVE_HSYNC,
+                       DSI_ACTIVE_HSYNC_START(hs_start) |
+                       DSI_ACTIVE_HSYNC_END(hs_end));
+               dsi_write(msm_host, REG_DSI_ACTIVE_VSYNC_HPOS, 0);
+               dsi_write(msm_host, REG_DSI_ACTIVE_VSYNC_VPOS,
+                       DSI_ACTIVE_VSYNC_VPOS_START(vs_start) |
+                       DSI_ACTIVE_VSYNC_VPOS_END(vs_end));
+       } else {                /* command mode */
+               /* image data and 1 byte write_memory_start cmd */
+               wc = mode->hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;
+
+               dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM_CTRL,
+                       DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT(wc) |
+                       DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL(
+                                       msm_host->channel) |
+                       DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE(
+                                       MIPI_DSI_DCS_LONG_WRITE));
+
+               dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM_TOTAL,
+                       DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL(mode->hdisplay) |
+                       DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL(mode->vdisplay));
+       }
+}
+
+static void dsi_sw_reset(struct msm_dsi_host *msm_host)
+{
+       dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS);
+       wmb(); /* clocks need to be enabled before reset */
+
+       dsi_write(msm_host, REG_DSI_RESET, 1);
+       wmb(); /* make sure reset happen */
+       dsi_write(msm_host, REG_DSI_RESET, 0);
+}
+
+static void dsi_op_mode_config(struct msm_dsi_host *msm_host,
+                                       bool video_mode, bool enable)
+{
+       u32 dsi_ctrl;
+
+       dsi_ctrl = dsi_read(msm_host, REG_DSI_CTRL);
+
+       if (!enable) {
+               dsi_ctrl &= ~(DSI_CTRL_ENABLE | DSI_CTRL_VID_MODE_EN |
+                               DSI_CTRL_CMD_MODE_EN);
+               dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_MDP_DONE |
+                                       DSI_IRQ_MASK_VIDEO_DONE, 0);
+       } else {
+               if (video_mode) {
+                       dsi_ctrl |= DSI_CTRL_VID_MODE_EN;
+               } else {                /* command mode */
+                       dsi_ctrl |= DSI_CTRL_CMD_MODE_EN;
+                       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_MDP_DONE, 1);
+               }
+               dsi_ctrl |= DSI_CTRL_ENABLE;
+       }
+
+       dsi_write(msm_host, REG_DSI_CTRL, dsi_ctrl);
+}
+
+static void dsi_set_tx_power_mode(int mode, struct msm_dsi_host *msm_host)
+{
+       u32 data;
+
+       data = dsi_read(msm_host, REG_DSI_CMD_DMA_CTRL);
+
+       if (mode == 0)
+               data &= ~DSI_CMD_DMA_CTRL_LOW_POWER;
+       else
+               data |= DSI_CMD_DMA_CTRL_LOW_POWER;
+
+       dsi_write(msm_host, REG_DSI_CMD_DMA_CTRL, data);
+}
+
+static void dsi_wait4video_done(struct msm_dsi_host *msm_host)
+{
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 1);
+
+       reinit_completion(&msm_host->video_comp);
+
+       wait_for_completion_timeout(&msm_host->video_comp,
+                       msecs_to_jiffies(70));
+
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 0);
+}
+
+static void dsi_wait4video_eng_busy(struct msm_dsi_host *msm_host)
+{
+       if (!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO))
+               return;
+
+       if (msm_host->power_on) {
+               dsi_wait4video_done(msm_host);
+               /* delay 4 ms to skip BLLP */
+               usleep_range(2000, 4000);
+       }
+}
+
+/* dsi_cmd */
+static int dsi_tx_buf_alloc(struct msm_dsi_host *msm_host, int size)
+{
+       struct drm_device *dev = msm_host->dev;
+       int ret;
+       u32 iova;
+
+       mutex_lock(&dev->struct_mutex);
+       msm_host->tx_gem_obj = msm_gem_new(dev, size, MSM_BO_UNCACHED);
+       if (IS_ERR(msm_host->tx_gem_obj)) {
+               ret = PTR_ERR(msm_host->tx_gem_obj);
+               pr_err("%s: failed to allocate gem, %d\n", __func__, ret);
+               msm_host->tx_gem_obj = NULL;
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
+       ret = msm_gem_get_iova_locked(msm_host->tx_gem_obj, 0, &iova);
+       if (ret) {
+               pr_err("%s: failed to get iova, %d\n", __func__, ret);
+               return ret;
+       }
+       mutex_unlock(&dev->struct_mutex);
+
+       if (iova & 0x07) {
+               pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void dsi_tx_buf_free(struct msm_dsi_host *msm_host)
+{
+       struct drm_device *dev = msm_host->dev;
+
+       if (msm_host->tx_gem_obj) {
+               msm_gem_put_iova(msm_host->tx_gem_obj, 0);
+               mutex_lock(&dev->struct_mutex);
+               msm_gem_free_object(msm_host->tx_gem_obj);
+               msm_host->tx_gem_obj = NULL;
+               mutex_unlock(&dev->struct_mutex);
+       }
+}
+
+/*
+ * prepare cmd buffer to be txed
+ */
+static int dsi_cmd_dma_add(struct drm_gem_object *tx_gem,
+                       const struct mipi_dsi_msg *msg)
+{
+       struct mipi_dsi_packet packet;
+       int len;
+       int ret;
+       u8 *data;
+
+       ret = mipi_dsi_create_packet(&packet, msg);
+       if (ret) {
+               pr_err("%s: create packet failed, %d\n", __func__, ret);
+               return ret;
+       }
+       len = (packet.size + 3) & (~0x3);
+
+       if (len > tx_gem->size) {
+               pr_err("%s: packet size is too big\n", __func__);
+               return -EINVAL;
+       }
+
+       data = msm_gem_vaddr(tx_gem);
+
+       if (IS_ERR(data)) {
+               ret = PTR_ERR(data);
+               pr_err("%s: get vaddr failed, %d\n", __func__, ret);
+               return ret;
+       }
+
+       /* MSM specific command format in memory */
+       data[0] = packet.header[1];
+       data[1] = packet.header[2];
+       data[2] = packet.header[0];
+       data[3] = BIT(7); /* Last packet */
+       if (mipi_dsi_packet_format_is_long(msg->type))
+               data[3] |= BIT(6);
+       if (msg->rx_buf && msg->rx_len)
+               data[3] |= BIT(5);
+
+       /* Long packet */
+       if (packet.payload && packet.payload_length)
+               memcpy(data + 4, packet.payload, packet.payload_length);
+
+       /* Append 0xff to the end */
+       if (packet.size < len)
+               memset(data + packet.size, 0xff, len - packet.size);
+
+       return len;
+}
+
+/*
+ * dsi_short_read1_resp: 1 parameter
+ */
+static int dsi_short_read1_resp(u8 *buf, const struct mipi_dsi_msg *msg)
+{
+       u8 *data = msg->rx_buf;
+       if (data && (msg->rx_len >= 1)) {
+               *data = buf[1]; /* strip out dcs type */
+               return 1;
+       } else {
+               pr_err("%s: read data does not match with rx_buf len %d\n",
+                       __func__, msg->rx_len);
+               return -EINVAL;
+       }
+}
+
+/*
+ * dsi_short_read2_resp: 2 parameter
+ */
+static int dsi_short_read2_resp(u8 *buf, const struct mipi_dsi_msg *msg)
+{
+       u8 *data = msg->rx_buf;
+       if (data && (msg->rx_len >= 2)) {
+               data[0] = buf[1]; /* strip out dcs type */
+               data[1] = buf[2];
+               return 2;
+       } else {
+               pr_err("%s: read data does not match with rx_buf len %d\n",
+                       __func__, msg->rx_len);
+               return -EINVAL;
+       }
+}
+
+static int dsi_long_read_resp(u8 *buf, const struct mipi_dsi_msg *msg)
+{
+       /* strip out 4 byte dcs header */
+       if (msg->rx_buf && msg->rx_len)
+               memcpy(msg->rx_buf, buf + 4, msg->rx_len);
+
+       return msg->rx_len;
+}
+
+
+static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len)
+{
+       int ret;
+       u32 iova;
+       bool triggered;
+
+       ret = msm_gem_get_iova(msm_host->tx_gem_obj, 0, &iova);
+       if (ret) {
+               pr_err("%s: failed to get iova: %d\n", __func__, ret);
+               return ret;
+       }
+
+       reinit_completion(&msm_host->dma_comp);
+
+       dsi_wait4video_eng_busy(msm_host);
+
+       triggered = msm_dsi_manager_cmd_xfer_trigger(
+                                               msm_host->id, iova, len);
+       if (triggered) {
+               ret = wait_for_completion_timeout(&msm_host->dma_comp,
+                                       msecs_to_jiffies(200));
+               DBG("ret=%d", ret);
+               if (ret == 0)
+                       ret = -ETIMEDOUT;
+               else
+                       ret = len;
+       } else
+               ret = len;
+
+       return ret;
+}
+
+static int dsi_cmd_dma_rx(struct msm_dsi_host *msm_host,
+                       u8 *buf, int rx_byte, int pkt_size)
+{
+       u32 *lp, *temp, data;
+       int i, j = 0, cnt;
+       bool ack_error = false;
+       u32 read_cnt;
+       u8 reg[16];
+       int repeated_bytes = 0;
+       int buf_offset = buf - msm_host->rx_buf;
+
+       lp = (u32 *)buf;
+       temp = (u32 *)reg;
+       cnt = (rx_byte + 3) >> 2;
+       if (cnt > 4)
+               cnt = 4; /* 4 x 32 bits registers only */
+
+       /* Calculate real read data count */
+       read_cnt = dsi_read(msm_host, 0x1d4) >> 16;
+
+       ack_error = (rx_byte == 4) ?
+               (read_cnt == 8) : /* short pkt + 4-byte error pkt */
+               (read_cnt == (pkt_size + 6 + 4)); /* long pkt+4-byte error pkt*/
+
+       if (ack_error)
+               read_cnt -= 4; /* Remove 4 byte error pkt */
+
+       /*
+        * In case of multiple reads from the panel, after the first read, there
+        * is possibility that there are some bytes in the payload repeating in
+        * the RDBK_DATA registers. Since we read all the parameters from the
+        * panel right from the first byte for every pass. We need to skip the
+        * repeating bytes and then append the new parameters to the rx buffer.
+        */
+       if (read_cnt > 16) {
+               int bytes_shifted;
+               /* Any data more than 16 bytes will be shifted out.
+                * The temp read buffer should already contain these bytes.
+                * The remaining bytes in read buffer are the repeated bytes.
+                */
+               bytes_shifted = read_cnt - 16;
+               repeated_bytes = buf_offset - bytes_shifted;
+       }
+
+       for (i = cnt - 1; i >= 0; i--) {
+               data = dsi_read(msm_host, REG_DSI_RDBK_DATA(i));
+               *temp++ = ntohl(data); /* to host byte order */
+               DBG("data = 0x%x and ntohl(data) = 0x%x", data, ntohl(data));
+       }
+
+       for (i = repeated_bytes; i < 16; i++)
+               buf[j++] = reg[i];
+
+       return j;
+}
+
+static int dsi_cmds2buf_tx(struct msm_dsi_host *msm_host,
+                               const struct mipi_dsi_msg *msg)
+{
+       int len, ret;
+       int bllp_len = msm_host->mode->hdisplay *
+                       dsi_get_bpp(msm_host->format) / 8;
+
+       len = dsi_cmd_dma_add(msm_host->tx_gem_obj, msg);
+       if (!len) {
+               pr_err("%s: failed to add cmd type = 0x%x\n",
+                       __func__,  msg->type);
+               return -EINVAL;
+       }
+
+       /* for video mode, do not send cmds more than
+       * one pixel line, since it only transmit it
+       * during BLLP.
+       */
+       /* TODO: if the command is sent in LP mode, the bit rate is only
+        * half of esc clk rate. In this case, if the video is already
+        * actively streaming, we need to check more carefully if the
+        * command can be fit into one BLLP.
+        */
+       if ((msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) && (len > bllp_len)) {
+               pr_err("%s: cmd cannot fit into BLLP period, len=%d\n",
+                       __func__, len);
+               return -EINVAL;
+       }
+
+       ret = dsi_cmd_dma_tx(msm_host, len);
+       if (ret < len) {
+               pr_err("%s: cmd dma tx failed, type=0x%x, data0=0x%x, len=%d\n",
+                       __func__, msg->type, (*(u8 *)(msg->tx_buf)), len);
+               return -ECOMM;
+       }
+
+       return len;
+}
+
+static void dsi_sw_reset_restore(struct msm_dsi_host *msm_host)
+{
+       u32 data0, data1;
+
+       data0 = dsi_read(msm_host, REG_DSI_CTRL);
+       data1 = data0;
+       data1 &= ~DSI_CTRL_ENABLE;
+       dsi_write(msm_host, REG_DSI_CTRL, data1);
+       /*
+        * dsi controller need to be disabled before
+        * clocks turned on
+        */
+       wmb();
+
+       dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS);
+       wmb();  /* make sure clocks enabled */
+
+       /* dsi controller can only be reset while clocks are running */
+       dsi_write(msm_host, REG_DSI_RESET, 1);
+       wmb();  /* make sure reset happen */
+       dsi_write(msm_host, REG_DSI_RESET, 0);
+       wmb();  /* controller out of reset */
+       dsi_write(msm_host, REG_DSI_CTRL, data0);
+       wmb();  /* make sure dsi controller enabled again */
+}
+
+static void dsi_err_worker(struct work_struct *work)
+{
+       struct msm_dsi_host *msm_host =
+               container_of(work, struct msm_dsi_host, err_work);
+       u32 status = msm_host->err_work_state;
+
+       pr_err("%s: status=%x\n", __func__, status);
+       if (status & DSI_ERR_STATE_MDP_FIFO_UNDERFLOW)
+               dsi_sw_reset_restore(msm_host);
+
+       /* It is safe to clear here because error irq is disabled. */
+       msm_host->err_work_state = 0;
+
+       /* enable dsi error interrupt */
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, 1);
+}
+
+static void dsi_ack_err_status(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_ACK_ERR_STATUS);
+
+       if (status) {
+               dsi_write(msm_host, REG_DSI_ACK_ERR_STATUS, status);
+               /* Writing of an extra 0 needed to clear error bits */
+               dsi_write(msm_host, REG_DSI_ACK_ERR_STATUS, 0);
+               msm_host->err_work_state |= DSI_ERR_STATE_ACK;
+       }
+}
+
+static void dsi_timeout_status(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_TIMEOUT_STATUS);
+
+       if (status) {
+               dsi_write(msm_host, REG_DSI_TIMEOUT_STATUS, status);
+               msm_host->err_work_state |= DSI_ERR_STATE_TIMEOUT;
+       }
+}
+
+static void dsi_dln0_phy_err(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_DLN0_PHY_ERR);
+
+       if (status) {
+               dsi_write(msm_host, REG_DSI_DLN0_PHY_ERR, status);
+               msm_host->err_work_state |= DSI_ERR_STATE_DLN0_PHY;
+       }
+}
+
+static void dsi_fifo_status(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_FIFO_STATUS);
+
+       /* fifo underflow, overflow */
+       if (status) {
+               dsi_write(msm_host, REG_DSI_FIFO_STATUS, status);
+               msm_host->err_work_state |= DSI_ERR_STATE_FIFO;
+               if (status & DSI_FIFO_STATUS_CMD_MDP_FIFO_UNDERFLOW)
+                       msm_host->err_work_state |=
+                                       DSI_ERR_STATE_MDP_FIFO_UNDERFLOW;
+       }
+}
+
+static void dsi_status(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_STATUS0);
+
+       if (status & DSI_STATUS0_INTERLEAVE_OP_CONTENTION) {
+               dsi_write(msm_host, REG_DSI_STATUS0, status);
+               msm_host->err_work_state |=
+                       DSI_ERR_STATE_INTERLEAVE_OP_CONTENTION;
+       }
+}
+
+static void dsi_clk_status(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_CLK_STATUS);
+
+       if (status & DSI_CLK_STATUS_PLL_UNLOCKED) {
+               dsi_write(msm_host, REG_DSI_CLK_STATUS, status);
+               msm_host->err_work_state |= DSI_ERR_STATE_PLL_UNLOCKED;
+       }
+}
+
+static void dsi_error(struct msm_dsi_host *msm_host)
+{
+       /* disable dsi error interrupt */
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, 0);
+
+       dsi_clk_status(msm_host);
+       dsi_fifo_status(msm_host);
+       dsi_ack_err_status(msm_host);
+       dsi_timeout_status(msm_host);
+       dsi_status(msm_host);
+       dsi_dln0_phy_err(msm_host);
+
+       queue_work(msm_host->workqueue, &msm_host->err_work);
+}
+
+static irqreturn_t dsi_host_irq(int irq, void *ptr)
+{
+       struct msm_dsi_host *msm_host = ptr;
+       u32 isr;
+       unsigned long flags;
+
+       if (!msm_host->ctrl_base)
+               return IRQ_HANDLED;
+
+       spin_lock_irqsave(&msm_host->intr_lock, flags);
+       isr = dsi_read(msm_host, REG_DSI_INTR_CTRL);
+       dsi_write(msm_host, REG_DSI_INTR_CTRL, isr);
+       spin_unlock_irqrestore(&msm_host->intr_lock, flags);
+
+       DBG("isr=0x%x, id=%d", isr, msm_host->id);
+
+       if (isr & DSI_IRQ_ERROR)
+               dsi_error(msm_host);
+
+       if (isr & DSI_IRQ_VIDEO_DONE)
+               complete(&msm_host->video_comp);
+
+       if (isr & DSI_IRQ_CMD_DMA_DONE)
+               complete(&msm_host->dma_comp);
+
+       return IRQ_HANDLED;
+}
+
+static int dsi_host_init_panel_gpios(struct msm_dsi_host *msm_host,
+                       struct device *panel_device)
+{
+       int ret;
+
+       msm_host->disp_en_gpio = devm_gpiod_get(panel_device,
+                                               "disp-enable");
+       if (IS_ERR(msm_host->disp_en_gpio)) {
+               DBG("cannot get disp-enable-gpios %ld",
+                               PTR_ERR(msm_host->disp_en_gpio));
+               msm_host->disp_en_gpio = NULL;
+       }
+       if (msm_host->disp_en_gpio) {
+               ret = gpiod_direction_output(msm_host->disp_en_gpio, 0);
+               if (ret) {
+                       pr_err("cannot set dir to disp-en-gpios %d\n", ret);
+                       return ret;
+               }
+       }
+
+       msm_host->te_gpio = devm_gpiod_get(panel_device, "disp-te");
+       if (IS_ERR(msm_host->te_gpio)) {
+               DBG("cannot get disp-te-gpios %ld", PTR_ERR(msm_host->te_gpio));
+               msm_host->te_gpio = NULL;
+       }
+
+       if (msm_host->te_gpio) {
+               ret = gpiod_direction_input(msm_host->te_gpio);
+               if (ret) {
+                       pr_err("%s: cannot set dir to disp-te-gpios, %d\n",
+                               __func__, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int dsi_host_attach(struct mipi_dsi_host *host,
+                                       struct mipi_dsi_device *dsi)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       int ret;
+
+       msm_host->channel = dsi->channel;
+       msm_host->lanes = dsi->lanes;
+       msm_host->format = dsi->format;
+       msm_host->mode_flags = dsi->mode_flags;
+
+       msm_host->panel_node = dsi->dev.of_node;
+
+       /* Some gpios defined in panel DT need to be controlled by host */
+       ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev);
+       if (ret)
+               return ret;
+
+       DBG("id=%d", msm_host->id);
+       if (msm_host->dev)
+               drm_helper_hpd_irq_event(msm_host->dev);
+
+       return 0;
+}
+
+static int dsi_host_detach(struct mipi_dsi_host *host,
+                                       struct mipi_dsi_device *dsi)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       msm_host->panel_node = NULL;
+
+       DBG("id=%d", msm_host->id);
+       if (msm_host->dev)
+               drm_helper_hpd_irq_event(msm_host->dev);
+
+       return 0;
+}
+
+static ssize_t dsi_host_transfer(struct mipi_dsi_host *host,
+                                       const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       int ret;
+
+       if (!msg || !msm_host->power_on)
+               return -EINVAL;
+
+       mutex_lock(&msm_host->cmd_mutex);
+       ret = msm_dsi_manager_cmd_xfer(msm_host->id, msg);
+       mutex_unlock(&msm_host->cmd_mutex);
+
+       return ret;
+}
+
+static struct mipi_dsi_host_ops dsi_host_ops = {
+       .attach = dsi_host_attach,
+       .detach = dsi_host_detach,
+       .transfer = dsi_host_transfer,
+};
+
+int msm_dsi_host_init(struct msm_dsi *msm_dsi)
+{
+       struct msm_dsi_host *msm_host = NULL;
+       struct platform_device *pdev = msm_dsi->pdev;
+       int ret;
+
+       msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
+       if (!msm_host) {
+               pr_err("%s: FAILED: cannot alloc dsi host\n",
+                      __func__);
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = of_property_read_u32(pdev->dev.of_node,
+                               "qcom,dsi-host-index", &msm_host->id);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "%s: host index not specified, ret=%d\n",
+                       __func__, ret);
+               goto fail;
+       }
+       msm_host->pdev = pdev;
+
+       ret = dsi_clk_init(msm_host);
+       if (ret) {
+               pr_err("%s: unable to initialize dsi clks\n", __func__);
+               goto fail;
+       }
+
+       msm_host->ctrl_base = msm_ioremap(pdev, "dsi_ctrl", "DSI CTRL");
+       if (IS_ERR(msm_host->ctrl_base)) {
+               pr_err("%s: unable to map Dsi ctrl base\n", __func__);
+               ret = PTR_ERR(msm_host->ctrl_base);
+               goto fail;
+       }
+
+       msm_host->cfg = dsi_get_config(msm_host);
+       if (!msm_host->cfg) {
+               ret = -EINVAL;
+               pr_err("%s: get config failed\n", __func__);
+               goto fail;
+       }
+
+       ret = dsi_regulator_init(msm_host);
+       if (ret) {
+               pr_err("%s: regulator init failed\n", __func__);
+               goto fail;
+       }
+
+       msm_host->rx_buf = devm_kzalloc(&pdev->dev, SZ_4K, GFP_KERNEL);
+       if (!msm_host->rx_buf) {
+               pr_err("%s: alloc rx temp buf failed\n", __func__);
+               goto fail;
+       }
+
+       init_completion(&msm_host->dma_comp);
+       init_completion(&msm_host->video_comp);
+       mutex_init(&msm_host->dev_mutex);
+       mutex_init(&msm_host->cmd_mutex);
+       mutex_init(&msm_host->clk_mutex);
+       spin_lock_init(&msm_host->intr_lock);
+
+       /* setup workqueue */
+       msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0);
+       INIT_WORK(&msm_host->err_work, dsi_err_worker);
+
+       msm_dsi->phy = msm_dsi_phy_init(pdev, msm_host->cfg->phy_type,
+                                       msm_host->id);
+       if (!msm_dsi->phy) {
+               ret = -EINVAL;
+               pr_err("%s: phy init failed\n", __func__);
+               goto fail;
+       }
+       msm_dsi->host = &msm_host->base;
+       msm_dsi->id = msm_host->id;
+
+       DBG("Dsi Host %d initialized", msm_host->id);
+       return 0;
+
+fail:
+       return ret;
+}
+
+void msm_dsi_host_destroy(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       DBG("");
+       dsi_tx_buf_free(msm_host);
+       if (msm_host->workqueue) {
+               flush_workqueue(msm_host->workqueue);
+               destroy_workqueue(msm_host->workqueue);
+               msm_host->workqueue = NULL;
+       }
+
+       mutex_destroy(&msm_host->clk_mutex);
+       mutex_destroy(&msm_host->cmd_mutex);
+       mutex_destroy(&msm_host->dev_mutex);
+}
+
+int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
+                                       struct drm_device *dev)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       struct platform_device *pdev = msm_host->pdev;
+       int ret;
+
+       msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+       if (msm_host->irq < 0) {
+               ret = msm_host->irq;
+               dev_err(dev->dev, "failed to get irq: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_request_irq(&pdev->dev, msm_host->irq,
+                       dsi_host_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                       "dsi_isr", msm_host);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to request IRQ%u: %d\n",
+                               msm_host->irq, ret);
+               return ret;
+       }
+
+       msm_host->dev = dev;
+       ret = dsi_tx_buf_alloc(msm_host, SZ_4K);
+       if (ret) {
+               pr_err("%s: alloc tx gem obj failed, %d\n", __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       struct device_node *node;
+       int ret;
+
+       /* Register mipi dsi host */
+       if (!msm_host->registered) {
+               host->dev = &msm_host->pdev->dev;
+               host->ops = &dsi_host_ops;
+               ret = mipi_dsi_host_register(host);
+               if (ret)
+                       return ret;
+
+               msm_host->registered = true;
+
+               /* If the panel driver has not been probed after host register,
+                * we should defer the host's probe.
+                * It makes sure panel is connected when fbcon detects
+                * connector status and gets the proper display mode to
+                * create framebuffer.
+                */
+               if (check_defer) {
+                       node = of_get_child_by_name(msm_host->pdev->dev.of_node,
+                                                       "panel");
+                       if (node) {
+                               if (!of_drm_find_panel(node))
+                                       return -EPROBE_DEFER;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+void msm_dsi_host_unregister(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       if (msm_host->registered) {
+               mipi_dsi_host_unregister(host);
+               host->dev = NULL;
+               host->ops = NULL;
+               msm_host->registered = false;
+       }
+}
+
+int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
+                               const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       /* TODO: make sure dsi_cmd_mdp is idle.
+        * Since DSI6G v1.2.0, we can set DSI_TRIG_CTRL.BLOCK_DMA_WITHIN_FRAME
+        * to ask H/W to wait until cmd mdp is idle. S/W wait is not needed.
+        * How to handle the old versions? Wait for mdp cmd done?
+        */
+
+       /*
+        * mdss interrupt is generated in mdp core clock domain
+        * mdp clock need to be enabled to receive dsi interrupt
+        */
+       dsi_clk_ctrl(msm_host, 1);
+
+       /* TODO: vote for bus bandwidth */
+
+       if (!(msg->flags & MIPI_DSI_MSG_USE_LPM))
+               dsi_set_tx_power_mode(0, msm_host);
+
+       msm_host->dma_cmd_ctrl_restore = dsi_read(msm_host, REG_DSI_CTRL);
+       dsi_write(msm_host, REG_DSI_CTRL,
+               msm_host->dma_cmd_ctrl_restore |
+               DSI_CTRL_CMD_MODE_EN |
+               DSI_CTRL_ENABLE);
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_DMA_DONE, 1);
+
+       return 0;
+}
+
+void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host,
+                               const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_DMA_DONE, 0);
+       dsi_write(msm_host, REG_DSI_CTRL, msm_host->dma_cmd_ctrl_restore);
+
+       if (!(msg->flags & MIPI_DSI_MSG_USE_LPM))
+               dsi_set_tx_power_mode(1, msm_host);
+
+       /* TODO: unvote for bus bandwidth */
+
+       dsi_clk_ctrl(msm_host, 0);
+}
+
+int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host,
+                               const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       return dsi_cmds2buf_tx(msm_host, msg);
+}
+
+int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
+                               const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       int data_byte, rx_byte, dlen, end;
+       int short_response, diff, pkt_size, ret = 0;
+       char cmd;
+       int rlen = msg->rx_len;
+       u8 *buf;
+
+       if (rlen <= 2) {
+               short_response = 1;
+               pkt_size = rlen;
+               rx_byte = 4;
+       } else {
+               short_response = 0;
+               data_byte = 10; /* first read */
+               if (rlen < data_byte)
+                       pkt_size = rlen;
+               else
+                       pkt_size = data_byte;
+               rx_byte = data_byte + 6; /* 4 header + 2 crc */
+       }
+
+       buf = msm_host->rx_buf;
+       end = 0;
+       while (!end) {
+               u8 tx[2] = {pkt_size & 0xff, pkt_size >> 8};
+               struct mipi_dsi_msg max_pkt_size_msg = {
+                       .channel = msg->channel,
+                       .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
+                       .tx_len = 2,
+                       .tx_buf = tx,
+               };
+
+               DBG("rlen=%d pkt_size=%d rx_byte=%d",
+                       rlen, pkt_size, rx_byte);
+
+               ret = dsi_cmds2buf_tx(msm_host, &max_pkt_size_msg);
+               if (ret < 2) {
+                       pr_err("%s: Set max pkt size failed, %d\n",
+                               __func__, ret);
+                       return -EINVAL;
+               }
+
+               if ((msm_host->cfg->major == MSM_DSI_VER_MAJOR_6G) &&
+                       (msm_host->cfg->minor >= MSM_DSI_6G_VER_MINOR_V1_1)) {
+                       /* Clear the RDBK_DATA registers */
+                       dsi_write(msm_host, REG_DSI_RDBK_DATA_CTRL,
+                                       DSI_RDBK_DATA_CTRL_CLR);
+                       wmb(); /* make sure the RDBK registers are cleared */
+                       dsi_write(msm_host, REG_DSI_RDBK_DATA_CTRL, 0);
+                       wmb(); /* release cleared status before transfer */
+               }
+
+               ret = dsi_cmds2buf_tx(msm_host, msg);
+               if (ret < msg->tx_len) {
+                       pr_err("%s: Read cmd Tx failed, %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /*
+                * once cmd_dma_done interrupt received,
+                * return data from client is ready and stored
+                * at RDBK_DATA register already
+                * since rx fifo is 16 bytes, dcs header is kept at first loop,
+                * after that dcs header lost during shift into registers
+                */
+               dlen = dsi_cmd_dma_rx(msm_host, buf, rx_byte, pkt_size);
+
+               if (dlen <= 0)
+                       return 0;
+
+               if (short_response)
+                       break;
+
+               if (rlen <= data_byte) {
+                       diff = data_byte - rlen;
+                       end = 1;
+               } else {
+                       diff = 0;
+                       rlen -= data_byte;
+               }
+
+               if (!end) {
+                       dlen -= 2; /* 2 crc */
+                       dlen -= diff;
+                       buf += dlen;    /* next start position */
+                       data_byte = 14; /* NOT first read */
+                       if (rlen < data_byte)
+                               pkt_size += rlen;
+                       else
+                               pkt_size += data_byte;
+                       DBG("buf=%p dlen=%d diff=%d", buf, dlen, diff);
+               }
+       }
+
+       /*
+        * For single Long read, if the requested rlen < 10,
+        * we need to shift the start position of rx
+        * data buffer to skip the bytes which are not
+        * updated.
+        */
+       if (pkt_size < 10 && !short_response)
+               buf = msm_host->rx_buf + (10 - rlen);
+       else
+               buf = msm_host->rx_buf;
+
+       cmd = buf[0];
+       switch (cmd) {
+       case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+               pr_err("%s: rx ACK_ERR_PACLAGE\n", __func__);
+               ret = 0;
+       case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+       case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+               ret = dsi_short_read1_resp(buf, msg);
+               break;
+       case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+       case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+               ret = dsi_short_read2_resp(buf, msg);
+               break;
+       case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
+       case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
+               ret = dsi_long_read_resp(buf, msg);
+               break;
+       default:
+               pr_warn("%s:Invalid response cmd\n", __func__);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 iova, u32 len)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       dsi_write(msm_host, REG_DSI_DMA_BASE, iova);
+       dsi_write(msm_host, REG_DSI_DMA_LEN, len);
+       dsi_write(msm_host, REG_DSI_TRIG_DMA, 1);
+
+       /* Make sure trigger happens */
+       wmb();
+}
+
+int msm_dsi_host_enable(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       dsi_op_mode_config(msm_host,
+               !!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO), true);
+
+       /* TODO: clock should be turned off for command mode,
+        * and only turned on before MDP START.
+        * This part of code should be enabled once mdp driver support it.
+        */
+       /* if (msm_panel->mode == MSM_DSI_CMD_MODE)
+               dsi_clk_ctrl(msm_host, 0); */
+
+       return 0;
+}
+
+int msm_dsi_host_disable(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       dsi_op_mode_config(msm_host,
+               !!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO), false);
+
+       /* Since we have disabled INTF, the video engine won't stop so that
+        * the cmd engine will be blocked.
+        * Reset to disable video engine so that we can send off cmd.
+        */
+       dsi_sw_reset(msm_host);
+
+       return 0;
+}
+
+int msm_dsi_host_power_on(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       u32 clk_pre = 0, clk_post = 0;
+       int ret = 0;
+
+       mutex_lock(&msm_host->dev_mutex);
+       if (msm_host->power_on) {
+               DBG("dsi host already on");
+               goto unlock_ret;
+       }
+
+       ret = dsi_calc_clk_rate(msm_host);
+       if (ret) {
+               pr_err("%s: unable to calc clk rate, %d\n", __func__, ret);
+               goto unlock_ret;
+       }
+
+       ret = dsi_host_regulator_enable(msm_host);
+       if (ret) {
+               pr_err("%s:Failed to enable vregs.ret=%d\n",
+                       __func__, ret);
+               goto unlock_ret;
+       }
+
+       ret = dsi_bus_clk_enable(msm_host);
+       if (ret) {
+               pr_err("%s: failed to enable bus clocks, %d\n", __func__, ret);
+               goto fail_disable_reg;
+       }
+
+       dsi_phy_sw_reset(msm_host);
+       ret = msm_dsi_manager_phy_enable(msm_host->id,
+                                       msm_host->byte_clk_rate * 8,
+                                       clk_get_rate(msm_host->esc_clk),
+                                       &clk_pre, &clk_post);
+       dsi_bus_clk_disable(msm_host);
+       if (ret) {
+               pr_err("%s: failed to enable phy, %d\n", __func__, ret);
+               goto fail_disable_reg;
+       }
+
+       ret = dsi_clk_ctrl(msm_host, 1);
+       if (ret) {
+               pr_err("%s: failed to enable clocks. ret=%d\n", __func__, ret);
+               goto fail_disable_reg;
+       }
+
+       dsi_timing_setup(msm_host);
+       dsi_sw_reset(msm_host);
+       dsi_ctrl_config(msm_host, true, clk_pre, clk_post);
+
+       if (msm_host->disp_en_gpio)
+               gpiod_set_value(msm_host->disp_en_gpio, 1);
+
+       msm_host->power_on = true;
+       mutex_unlock(&msm_host->dev_mutex);
+
+       return 0;
+
+fail_disable_reg:
+       dsi_host_regulator_disable(msm_host);
+unlock_ret:
+       mutex_unlock(&msm_host->dev_mutex);
+       return ret;
+}
+
+int msm_dsi_host_power_off(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       mutex_lock(&msm_host->dev_mutex);
+       if (!msm_host->power_on) {
+               DBG("dsi host already off");
+               goto unlock_ret;
+       }
+
+       dsi_ctrl_config(msm_host, false, 0, 0);
+
+       if (msm_host->disp_en_gpio)
+               gpiod_set_value(msm_host->disp_en_gpio, 0);
+
+       msm_dsi_manager_phy_disable(msm_host->id);
+
+       dsi_clk_ctrl(msm_host, 0);
+
+       dsi_host_regulator_disable(msm_host);
+
+       DBG("-");
+
+       msm_host->power_on = false;
+
+unlock_ret:
+       mutex_unlock(&msm_host->dev_mutex);
+       return 0;
+}
+
+int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
+                                       struct drm_display_mode *mode)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       if (msm_host->mode) {
+               drm_mode_destroy(msm_host->dev, msm_host->mode);
+               msm_host->mode = NULL;
+       }
+
+       msm_host->mode = drm_mode_duplicate(msm_host->dev, mode);
+       if (IS_ERR(msm_host->mode)) {
+               pr_err("%s: cannot duplicate mode\n", __func__);
+               return PTR_ERR(msm_host->mode);
+       }
+
+       return 0;
+}
+
+struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
+                               unsigned long *panel_flags)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       struct drm_panel *panel;
+
+       panel = of_drm_find_panel(msm_host->panel_node);
+       if (panel_flags)
+                       *panel_flags = msm_host->mode_flags;
+
+       return panel;
+}
+
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
new file mode 100644 (file)
index 0000000..ee3ebca
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm_kms.h"
+#include "dsi.h"
+
+struct msm_dsi_manager {
+       struct msm_dsi *dsi[DSI_MAX];
+
+       bool is_dual_panel;
+       bool is_sync_needed;
+       int master_panel_id;
+};
+
+static struct msm_dsi_manager msm_dsim_glb;
+
+#define IS_DUAL_PANEL()                (msm_dsim_glb.is_dual_panel)
+#define IS_SYNC_NEEDED()       (msm_dsim_glb.is_sync_needed)
+#define IS_MASTER_PANEL(id)    (msm_dsim_glb.master_panel_id == id)
+
+static inline struct msm_dsi *dsi_mgr_get_dsi(int id)
+{
+       return msm_dsim_glb.dsi[id];
+}
+
+static inline struct msm_dsi *dsi_mgr_get_other_dsi(int id)
+{
+       return msm_dsim_glb.dsi[(id + 1) % DSI_MAX];
+}
+
+static int dsi_mgr_parse_dual_panel(struct device_node *np, int id)
+{
+       struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
+
+       /* We assume 2 dsi nodes have the same information of dual-panel and
+        * sync-mode, and only one node specifies master in case of dual mode.
+        */
+       if (!msm_dsim->is_dual_panel)
+               msm_dsim->is_dual_panel = of_property_read_bool(
+                                               np, "qcom,dual-panel-mode");
+
+       if (msm_dsim->is_dual_panel) {
+               if (of_property_read_bool(np, "qcom,master-panel"))
+                       msm_dsim->master_panel_id = id;
+               if (!msm_dsim->is_sync_needed)
+                       msm_dsim->is_sync_needed = of_property_read_bool(
+                                       np, "qcom,sync-dual-panel");
+       }
+
+       return 0;
+}
+
+struct dsi_connector {
+       struct drm_connector base;
+       int id;
+};
+
+struct dsi_bridge {
+       struct drm_bridge base;
+       int id;
+};
+
+#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
+#define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
+
+static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
+{
+       struct dsi_connector *dsi_connector = to_dsi_connector(connector);
+       return dsi_connector->id;
+}
+
+static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
+{
+       struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
+       return dsi_bridge->id;
+}
+
+static enum drm_connector_status dsi_mgr_connector_detect(
+               struct drm_connector *connector, bool force)
+{
+       int id = dsi_mgr_connector_get_id(connector);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
+       struct msm_drm_private *priv = connector->dev->dev_private;
+       struct msm_kms *kms = priv->kms;
+
+       DBG("id=%d", id);
+       if (!msm_dsi->panel) {
+               msm_dsi->panel = msm_dsi_host_get_panel(msm_dsi->host,
+                                               &msm_dsi->panel_flags);
+
+               /* There is only 1 panel in the global panel list
+                * for dual panel mode. Therefore slave dsi should get
+                * the drm_panel instance from master dsi, and
+                * keep using the panel flags got from the current DSI link.
+                */
+               if (!msm_dsi->panel && IS_DUAL_PANEL() &&
+                       !IS_MASTER_PANEL(id) && other_dsi)
+                       msm_dsi->panel = msm_dsi_host_get_panel(
+                                       other_dsi->host, NULL);
+
+               if (msm_dsi->panel && IS_DUAL_PANEL())
+                       drm_object_attach_property(&connector->base,
+                               connector->dev->mode_config.tile_property, 0);
+
+               /* Set split display info to kms once dual panel is connected
+                * to both hosts
+                */
+               if (msm_dsi->panel && IS_DUAL_PANEL() &&
+                       other_dsi && other_dsi->panel) {
+                       bool cmd_mode = !(msm_dsi->panel_flags &
+                                               MIPI_DSI_MODE_VIDEO);
+                       struct drm_encoder *encoder = msm_dsi_get_encoder(
+                                       dsi_mgr_get_dsi(DSI_ENCODER_MASTER));
+                       struct drm_encoder *slave_enc = msm_dsi_get_encoder(
+                                       dsi_mgr_get_dsi(DSI_ENCODER_SLAVE));
+
+                       if (kms->funcs->set_split_display)
+                               kms->funcs->set_split_display(kms, encoder,
+                                                       slave_enc, cmd_mode);
+                       else
+                               pr_err("mdp does not support dual panel\n");
+               }
+       }
+
+       return msm_dsi->panel ? connector_status_connected :
+               connector_status_disconnected;
+}
+
+static void dsi_mgr_connector_destroy(struct drm_connector *connector)
+{
+       DBG("");
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
+}
+
+static void dsi_dual_connector_fix_modes(struct drm_connector *connector)
+{
+       struct drm_display_mode *mode, *m;
+
+       /* Only support left-right mode */
+       list_for_each_entry_safe(mode, m, &connector->probed_modes, head) {
+               mode->clock >>= 1;
+               mode->hdisplay >>= 1;
+               mode->hsync_start >>= 1;
+               mode->hsync_end >>= 1;
+               mode->htotal >>= 1;
+               drm_mode_set_name(mode);
+       }
+}
+
+static int dsi_dual_connector_tile_init(
+                       struct drm_connector *connector, int id)
+{
+       struct drm_display_mode *mode;
+       /* Fake topology id */
+       char topo_id[8] = {'M', 'S', 'M', 'D', 'U', 'D', 'S', 'I'};
+
+       if (connector->tile_group) {
+               DBG("Tile property has been initialized");
+               return 0;
+       }
+
+       /* Use the first mode only for now */
+       mode = list_first_entry(&connector->probed_modes,
+                               struct drm_display_mode,
+                               head);
+       if (!mode)
+               return -EINVAL;
+
+       connector->tile_group = drm_mode_get_tile_group(
+                                       connector->dev, topo_id);
+       if (!connector->tile_group)
+               connector->tile_group = drm_mode_create_tile_group(
+                                       connector->dev, topo_id);
+       if (!connector->tile_group) {
+               pr_err("%s: failed to create tile group\n", __func__);
+               return -ENOMEM;
+       }
+
+       connector->has_tile = true;
+       connector->tile_is_single_monitor = true;
+
+       /* mode has been fixed */
+       connector->tile_h_size = mode->hdisplay;
+       connector->tile_v_size = mode->vdisplay;
+
+       /* Only support left-right mode */
+       connector->num_h_tile = 2;
+       connector->num_v_tile = 1;
+
+       connector->tile_v_loc = 0;
+       connector->tile_h_loc = (id == DSI_RIGHT) ? 1 : 0;
+
+       return 0;
+}
+
+static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
+{
+       int id = dsi_mgr_connector_get_id(connector);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct drm_panel *panel = msm_dsi->panel;
+       int ret, num;
+
+       if (!panel)
+               return 0;
+
+       /* Since we have 2 connectors, but only 1 drm_panel in dual DSI mode,
+        * panel should not attach to any connector.
+        * Only temporarily attach panel to the current connector here,
+        * to let panel set mode to this connector.
+        */
+       drm_panel_attach(panel, connector);
+       num = drm_panel_get_modes(panel);
+       drm_panel_detach(panel);
+       if (!num)
+               return 0;
+
+       if (IS_DUAL_PANEL()) {
+               /* report half resolution to user */
+               dsi_dual_connector_fix_modes(connector);
+               ret = dsi_dual_connector_tile_init(connector, id);
+               if (ret)
+                       return ret;
+               ret = drm_mode_connector_set_tile_property(connector);
+               if (ret) {
+                       pr_err("%s: set tile property failed, %d\n",
+                                       __func__, ret);
+                       return ret;
+               }
+       }
+
+       return num;
+}
+
+static int dsi_mgr_connector_mode_valid(struct drm_connector *connector,
+                               struct drm_display_mode *mode)
+{
+       int id = dsi_mgr_connector_get_id(connector);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct drm_encoder *encoder = msm_dsi_get_encoder(msm_dsi);
+       struct msm_drm_private *priv = connector->dev->dev_private;
+       struct msm_kms *kms = priv->kms;
+       long actual, requested;
+
+       DBG("");
+       requested = 1000 * mode->clock;
+       actual = kms->funcs->round_pixclk(kms, requested, encoder);
+
+       DBG("requested=%ld, actual=%ld", requested, actual);
+       if (actual != requested)
+               return MODE_CLOCK_RANGE;
+
+       return MODE_OK;
+}
+
+static struct drm_encoder *
+dsi_mgr_connector_best_encoder(struct drm_connector *connector)
+{
+       int id = dsi_mgr_connector_get_id(connector);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+
+       DBG("");
+       return msm_dsi_get_encoder(msm_dsi);
+}
+
+static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
+{
+       int id = dsi_mgr_bridge_get_id(bridge);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
+       struct mipi_dsi_host *host = msm_dsi->host;
+       struct drm_panel *panel = msm_dsi->panel;
+       bool is_dual_panel = IS_DUAL_PANEL();
+       int ret;
+
+       DBG("id=%d", id);
+       if (!panel || (is_dual_panel && (DSI_1 == id)))
+               return;
+
+       ret = msm_dsi_host_power_on(host);
+       if (ret) {
+               pr_err("%s: power on host %d failed, %d\n", __func__, id, ret);
+               goto host_on_fail;
+       }
+
+       if (is_dual_panel && msm_dsi1) {
+               ret = msm_dsi_host_power_on(msm_dsi1->host);
+               if (ret) {
+                       pr_err("%s: power on host1 failed, %d\n",
+                                                       __func__, ret);
+                       goto host1_on_fail;
+               }
+       }
+
+       /* Always call panel functions once, because even for dual panels,
+        * there is only one drm_panel instance.
+        */
+       ret = drm_panel_prepare(panel);
+       if (ret) {
+               pr_err("%s: prepare panel %d failed, %d\n", __func__, id, ret);
+               goto panel_prep_fail;
+       }
+
+       ret = msm_dsi_host_enable(host);
+       if (ret) {
+               pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
+               goto host_en_fail;
+       }
+
+       if (is_dual_panel && msm_dsi1) {
+               ret = msm_dsi_host_enable(msm_dsi1->host);
+               if (ret) {
+                       pr_err("%s: enable host1 failed, %d\n", __func__, ret);
+                       goto host1_en_fail;
+               }
+       }
+
+       ret = drm_panel_enable(panel);
+       if (ret) {
+               pr_err("%s: enable panel %d failed, %d\n", __func__, id, ret);
+               goto panel_en_fail;
+       }
+
+       return;
+
+panel_en_fail:
+       if (is_dual_panel && msm_dsi1)
+               msm_dsi_host_disable(msm_dsi1->host);
+host1_en_fail:
+       msm_dsi_host_disable(host);
+host_en_fail:
+       drm_panel_unprepare(panel);
+panel_prep_fail:
+       if (is_dual_panel && msm_dsi1)
+               msm_dsi_host_power_off(msm_dsi1->host);
+host1_on_fail:
+       msm_dsi_host_power_off(host);
+host_on_fail:
+       return;
+}
+
+static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
+{
+       DBG("");
+}
+
+static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
+{
+       DBG("");
+}
+
+static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
+{
+       int id = dsi_mgr_bridge_get_id(bridge);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
+       struct mipi_dsi_host *host = msm_dsi->host;
+       struct drm_panel *panel = msm_dsi->panel;
+       bool is_dual_panel = IS_DUAL_PANEL();
+       int ret;
+
+       DBG("id=%d", id);
+
+       if (!panel || (is_dual_panel && (DSI_1 == id)))
+               return;
+
+       ret = drm_panel_disable(panel);
+       if (ret)
+               pr_err("%s: Panel %d OFF failed, %d\n", __func__, id, ret);
+
+       ret = msm_dsi_host_disable(host);
+       if (ret)
+               pr_err("%s: host %d disable failed, %d\n", __func__, id, ret);
+
+       if (is_dual_panel && msm_dsi1) {
+               ret = msm_dsi_host_disable(msm_dsi1->host);
+               if (ret)
+                       pr_err("%s: host1 disable failed, %d\n", __func__, ret);
+       }
+
+       ret = drm_panel_unprepare(panel);
+       if (ret)
+               pr_err("%s: Panel %d unprepare failed,%d\n", __func__, id, ret);
+
+       ret = msm_dsi_host_power_off(host);
+       if (ret)
+               pr_err("%s: host %d power off failed,%d\n", __func__, id, ret);
+
+       if (is_dual_panel && msm_dsi1) {
+               ret = msm_dsi_host_power_off(msm_dsi1->host);
+               if (ret)
+                       pr_err("%s: host1 power off failed, %d\n",
+                                                               __func__, ret);
+       }
+}
+
+static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       int id = dsi_mgr_bridge_get_id(bridge);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
+       struct mipi_dsi_host *host = msm_dsi->host;
+       bool is_dual_panel = IS_DUAL_PANEL();
+
+       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);
+
+       if (is_dual_panel && (DSI_1 == id))
+               return;
+
+       msm_dsi_host_set_display_mode(host, adjusted_mode);
+       if (is_dual_panel && other_dsi)
+               msm_dsi_host_set_display_mode(other_dsi->host, adjusted_mode);
+}
+
+static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
+       .dpms = drm_atomic_helper_connector_dpms,
+       .detect = dsi_mgr_connector_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = dsi_mgr_connector_destroy,
+       .reset = drm_atomic_helper_connector_reset,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
+       .get_modes = dsi_mgr_connector_get_modes,
+       .mode_valid = dsi_mgr_connector_mode_valid,
+       .best_encoder = dsi_mgr_connector_best_encoder,
+};
+
+static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
+       .pre_enable = dsi_mgr_bridge_pre_enable,
+       .enable = dsi_mgr_bridge_enable,
+       .disable = dsi_mgr_bridge_disable,
+       .post_disable = dsi_mgr_bridge_post_disable,
+       .mode_set = dsi_mgr_bridge_mode_set,
+};
+
+/* initialize connector */
+struct drm_connector *msm_dsi_manager_connector_init(u8 id)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct drm_connector *connector = NULL;
+       struct dsi_connector *dsi_connector;
+       int ret;
+
+       dsi_connector = devm_kzalloc(msm_dsi->dev->dev,
+                               sizeof(*dsi_connector), GFP_KERNEL);
+       if (!dsi_connector) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       dsi_connector->id = id;
+
+       connector = &dsi_connector->base;
+
+       ret = drm_connector_init(msm_dsi->dev, connector,
+                       &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
+       if (ret)
+               goto fail;
+
+       drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
+
+       /* Enable HPD to let hpd event is handled
+        * when panel is attached to the host.
+        */
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+       /* Display driver doesn't support interlace now. */
+       connector->interlace_allowed = 0;
+       connector->doublescan_allowed = 0;
+
+       ret = drm_connector_register(connector);
+       if (ret)
+               goto fail;
+
+       return connector;
+
+fail:
+       if (connector)
+               dsi_mgr_connector_destroy(connector);
+
+       return ERR_PTR(ret);
+}
+
+/* initialize bridge */
+struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct drm_bridge *bridge = NULL;
+       struct dsi_bridge *dsi_bridge;
+       int ret;
+
+       dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
+                               sizeof(*dsi_bridge), GFP_KERNEL);
+       if (!dsi_bridge) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       dsi_bridge->id = id;
+
+       bridge = &dsi_bridge->base;
+       bridge->funcs = &dsi_mgr_bridge_funcs;
+
+       ret = drm_bridge_attach(msm_dsi->dev, bridge);
+       if (ret)
+               goto fail;
+
+       return bridge;
+
+fail:
+       if (bridge)
+               msm_dsi_manager_bridge_destroy(bridge);
+
+       return ERR_PTR(ret);
+}
+
+void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
+{
+}
+
+int msm_dsi_manager_phy_enable(int id,
+               const unsigned long bit_rate, const unsigned long esc_rate,
+               u32 *clk_pre, u32 *clk_post)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi_phy *phy = msm_dsi->phy;
+       int ret;
+
+       ret = msm_dsi_phy_enable(phy, IS_DUAL_PANEL(), bit_rate, esc_rate);
+       if (ret)
+               return ret;
+
+       msm_dsi->phy_enabled = true;
+       msm_dsi_phy_get_clk_pre_post(phy, clk_pre, clk_post);
+
+       return 0;
+}
+
+void msm_dsi_manager_phy_disable(int id)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
+       struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
+       struct msm_dsi_phy *phy = msm_dsi->phy;
+
+       /* disable DSI phy
+        * In dual-dsi configuration, the phy should be disabled for the
+        * first controller only when the second controller is disabled.
+        */
+       msm_dsi->phy_enabled = false;
+       if (IS_DUAL_PANEL() && mdsi && sdsi) {
+               if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
+                       msm_dsi_phy_disable(sdsi->phy);
+                       msm_dsi_phy_disable(mdsi->phy);
+               }
+       } else {
+               msm_dsi_phy_disable(phy);
+       }
+}
+
+int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
+       struct mipi_dsi_host *host = msm_dsi->host;
+       bool is_read = (msg->rx_buf && msg->rx_len);
+       bool need_sync = (IS_SYNC_NEEDED() && !is_read);
+       int ret;
+
+       if (!msg->tx_buf || !msg->tx_len)
+               return 0;
+
+       /* In dual master case, panel requires the same commands sent to
+        * both DSI links. Host issues the command trigger to both links
+        * when DSI_1 calls the cmd transfer function, no matter it happens
+        * before or after DSI_0 cmd transfer.
+        */
+       if (need_sync && (id == DSI_0))
+               return is_read ? msg->rx_len : msg->tx_len;
+
+       if (need_sync && msm_dsi0) {
+               ret = msm_dsi_host_xfer_prepare(msm_dsi0->host, msg);
+               if (ret) {
+                       pr_err("%s: failed to prepare non-trigger host, %d\n",
+                               __func__, ret);
+                       return ret;
+               }
+       }
+       ret = msm_dsi_host_xfer_prepare(host, msg);
+       if (ret) {
+               pr_err("%s: failed to prepare host, %d\n", __func__, ret);
+               goto restore_host0;
+       }
+
+       ret = is_read ? msm_dsi_host_cmd_rx(host, msg) :
+                       msm_dsi_host_cmd_tx(host, msg);
+
+       msm_dsi_host_xfer_restore(host, msg);
+
+restore_host0:
+       if (need_sync && msm_dsi0)
+               msm_dsi_host_xfer_restore(msm_dsi0->host, msg);
+
+       return ret;
+}
+
+bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
+       struct mipi_dsi_host *host = msm_dsi->host;
+
+       if (IS_SYNC_NEEDED() && (id == DSI_0))
+               return false;
+
+       if (IS_SYNC_NEEDED() && msm_dsi0)
+               msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, iova, len);
+
+       msm_dsi_host_cmd_xfer_commit(host, iova, len);
+
+       return true;
+}
+
+int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
+{
+       struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
+       int id = msm_dsi->id;
+       struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
+       int ret;
+
+       if (id > DSI_MAX) {
+               pr_err("%s: invalid id %d\n", __func__, id);
+               return -EINVAL;
+       }
+
+       if (msm_dsim->dsi[id]) {
+               pr_err("%s: dsi%d already registered\n", __func__, id);
+               return -EBUSY;
+       }
+
+       msm_dsim->dsi[id] = msm_dsi;
+
+       ret = dsi_mgr_parse_dual_panel(msm_dsi->pdev->dev.of_node, id);
+       if (ret) {
+               pr_err("%s: failed to parse dual panel info\n", __func__);
+               return ret;
+       }
+
+       if (!IS_DUAL_PANEL()) {
+               ret = msm_dsi_host_register(msm_dsi->host, true);
+       } else if (!other_dsi) {
+               return 0;
+       } else {
+               struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ?
+                                       msm_dsi : other_dsi;
+               struct msm_dsi *sdsi = IS_MASTER_PANEL(id) ?
+                                       other_dsi : msm_dsi;
+               /* Register slave host first, so that slave DSI device
+                * has a chance to probe, and do not block the master
+                * DSI device's probe.
+                * Also, do not check defer for the slave host,
+                * because only master DSI device adds the panel to global
+                * panel list. The panel's device is the master DSI device.
+                */
+               ret = msm_dsi_host_register(sdsi->host, false);
+               if (ret)
+                       return ret;
+               ret = msm_dsi_host_register(mdsi->host, true);
+       }
+
+       return ret;
+}
+
+void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi)
+{
+       struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
+
+       if (msm_dsi->host)
+               msm_dsi_host_unregister(msm_dsi->host);
+       msm_dsim->dsi[msm_dsi->id] = NULL;
+}
+
diff --git a/drivers/gpu/drm/msm/dsi/dsi_phy.c b/drivers/gpu/drm/msm/dsi/dsi_phy.c
new file mode 100644 (file)
index 0000000..f0cea89
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "dsi.h"
+#include "dsi.xml.h"
+
+#define dsi_phy_read(offset) msm_readl((offset))
+#define dsi_phy_write(offset, data) msm_writel((data), (offset))
+
+struct dsi_dphy_timing {
+       u32 clk_pre;
+       u32 clk_post;
+       u32 clk_zero;
+       u32 clk_trail;
+       u32 clk_prepare;
+       u32 hs_exit;
+       u32 hs_zero;
+       u32 hs_prepare;
+       u32 hs_trail;
+       u32 hs_rqst;
+       u32 ta_go;
+       u32 ta_sure;
+       u32 ta_get;
+};
+
+struct msm_dsi_phy {
+       void __iomem *base;
+       void __iomem *reg_base;
+       int id;
+       struct dsi_dphy_timing timing;
+       int (*enable)(struct msm_dsi_phy *phy, bool is_dual_panel,
+               const unsigned long bit_rate, const unsigned long esc_rate);
+       int (*disable)(struct msm_dsi_phy *phy);
+};
+
+#define S_DIV_ROUND_UP(n, d)   \
+       (((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
+
+static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
+                               s32 min_result, bool even)
+{
+       s32 v;
+       v = (tmax - tmin) * percent;
+       v = S_DIV_ROUND_UP(v, 100) + tmin;
+       if (even && (v & 0x1))
+               return max_t(s32, min_result, v - 1);
+       else
+               return max_t(s32, min_result, v);
+}
+
+static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing,
+                                       s32 ui, s32 coeff, s32 pcnt)
+{
+       s32 tmax, tmin, clk_z;
+       s32 temp;
+
+       /* reset */
+       temp = 300 * coeff - ((timing->clk_prepare >> 1) + 1) * 2 * ui;
+       tmin = S_DIV_ROUND_UP(temp, ui) - 2;
+       if (tmin > 255) {
+               tmax = 511;
+               clk_z = linear_inter(2 * tmin, tmin, pcnt, 0, true);
+       } else {
+               tmax = 255;
+               clk_z = linear_inter(tmax, tmin, pcnt, 0, true);
+       }
+
+       /* adjust */
+       temp = (timing->hs_rqst + timing->clk_prepare + clk_z) & 0x7;
+       timing->clk_zero = clk_z + 8 - temp;
+}
+
+static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
+       const unsigned long bit_rate, const unsigned long esc_rate)
+{
+       s32 ui, lpx;
+       s32 tmax, tmin;
+       s32 pcnt0 = 10;
+       s32 pcnt1 = (bit_rate > 1200000000) ? 15 : 10;
+       s32 pcnt2 = 10;
+       s32 pcnt3 = (bit_rate > 180000000) ? 10 : 40;
+       s32 coeff = 1000; /* Precision, should avoid overflow */
+       s32 temp;
+
+       if (!bit_rate || !esc_rate)
+               return -EINVAL;
+
+       ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
+       lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
+
+       tmax = S_DIV_ROUND_UP(95 * coeff, ui) - 2;
+       tmin = S_DIV_ROUND_UP(38 * coeff, ui) - 2;
+       timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, true);
+
+       temp = lpx / ui;
+       if (temp & 0x1)
+               timing->hs_rqst = temp;
+       else
+               timing->hs_rqst = max_t(s32, 0, temp - 2);
+
+       /* Calculate clk_zero after clk_prepare and hs_rqst */
+       dsi_dphy_timing_calc_clk_zero(timing, ui, coeff, pcnt2);
+
+       temp = 105 * coeff + 12 * ui - 20 * coeff;
+       tmax = S_DIV_ROUND_UP(temp, ui) - 2;
+       tmin = S_DIV_ROUND_UP(60 * coeff, ui) - 2;
+       timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
+
+       temp = 85 * coeff + 6 * ui;
+       tmax = S_DIV_ROUND_UP(temp, ui) - 2;
+       temp = 40 * coeff + 4 * ui;
+       tmin = S_DIV_ROUND_UP(temp, ui) - 2;
+       timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, true);
+
+       tmax = 255;
+       temp = ((timing->hs_prepare >> 1) + 1) * 2 * ui + 2 * ui;
+       temp = 145 * coeff + 10 * ui - temp;
+       tmin = S_DIV_ROUND_UP(temp, ui) - 2;
+       timing->hs_zero = linear_inter(tmax, tmin, pcnt2, 24, true);
+
+       temp = 105 * coeff + 12 * ui - 20 * coeff;
+       tmax = S_DIV_ROUND_UP(temp, ui) - 2;
+       temp = 60 * coeff + 4 * ui;
+       tmin = DIV_ROUND_UP(temp, ui) - 2;
+       timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
+
+       tmax = 255;
+       tmin = S_DIV_ROUND_UP(100 * coeff, ui) - 2;
+       timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, true);
+
+       tmax = 63;
+       temp = ((timing->hs_exit >> 1) + 1) * 2 * ui;
+       temp = 60 * coeff + 52 * ui - 24 * ui - temp;
+       tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
+       timing->clk_post = linear_inter(tmax, tmin, pcnt2, 0, false);
+
+       tmax = 63;
+       temp = ((timing->clk_prepare >> 1) + 1) * 2 * ui;
+       temp += ((timing->clk_zero >> 1) + 1) * 2 * ui;
+       temp += 8 * ui + lpx;
+       tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
+       if (tmin > tmax) {
+               temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false) >> 1;
+               timing->clk_pre = temp >> 1;
+               temp = (2 * tmax - tmin) * pcnt2;
+       } else {
+               timing->clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false);
+       }
+
+       timing->ta_go = 3;
+       timing->ta_sure = 0;
+       timing->ta_get = 4;
+
+       DBG("PHY timings: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
+               timing->clk_pre, timing->clk_post, timing->clk_zero,
+               timing->clk_trail, timing->clk_prepare, timing->hs_exit,
+               timing->hs_zero, timing->hs_prepare, timing->hs_trail,
+               timing->hs_rqst);
+
+       return 0;
+}
+
+static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
+{
+       void __iomem *base = phy->reg_base;
+
+       if (!enable) {
+               dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
+               return;
+       }
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
+}
+
+static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
+               const unsigned long bit_rate, const unsigned long esc_rate)
+{
+       struct dsi_dphy_timing *timing = &phy->timing;
+       int i;
+       void __iomem *base = phy->base;
+
+       DBG("");
+
+       if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
+               pr_err("%s: D-PHY timing calculation failed\n", __func__);
+               return -EINVAL;
+       }
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff);
+
+       dsi_28nm_phy_regulator_ctrl(phy, true);
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00);
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0,
+               DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1,
+               DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2,
+               DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
+       if (timing->clk_zero & BIT(8))
+               dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3,
+                       DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4,
+               DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5,
+               DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6,
+               DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7,
+               DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8,
+               DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9,
+               DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
+               DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10,
+               DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11,
+               DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6);
+
+       for (i = 0; i < 4; i++) {
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97);
+       }
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(0), 0);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(1), 0x5);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(2), 0xa);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(3), 0xf);
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb);
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
+
+       if (is_dual_panel && (phy->id != DSI_CLOCK_MASTER))
+               dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 0x00);
+       else
+               dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 0x01);
+
+       return 0;
+}
+
+static int dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
+{
+       dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0);
+       dsi_28nm_phy_regulator_ctrl(phy, false);
+
+       /*
+        * Wait for the registers writes to complete in order to
+        * ensure that the phy is completely disabled
+        */
+       wmb();
+
+       return 0;
+}
+
+#define dsi_phy_func_init(name)        \
+       do {    \
+               phy->enable = dsi_##name##_phy_enable;  \
+               phy->disable = dsi_##name##_phy_disable;        \
+       } while (0)
+
+struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
+                       enum msm_dsi_phy_type type, int id)
+{
+       struct msm_dsi_phy *phy;
+
+       phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+       if (!phy)
+               return NULL;
+
+       phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
+       if (IS_ERR_OR_NULL(phy->base)) {
+               pr_err("%s: failed to map phy base\n", __func__);
+               return NULL;
+       }
+       phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG");
+       if (IS_ERR_OR_NULL(phy->reg_base)) {
+               pr_err("%s: failed to map phy regulator base\n", __func__);
+               return NULL;
+       }
+
+       switch (type) {
+       case MSM_DSI_PHY_28NM:
+               dsi_phy_func_init(28nm);
+               break;
+       default:
+               pr_err("%s: unsupported type, %d\n", __func__, type);
+               return NULL;
+       }
+
+       phy->id = id;
+
+       return phy;
+}
+
+int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
+       const unsigned long bit_rate, const unsigned long esc_rate)
+{
+       if (!phy || !phy->enable)
+               return -EINVAL;
+       return phy->enable(phy, is_dual_panel, bit_rate, esc_rate);
+}
+
+int msm_dsi_phy_disable(struct msm_dsi_phy *phy)
+{
+       if (!phy || !phy->disable)
+               return -EINVAL;
+       return phy->disable(phy);
+}
+
+void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
+       u32 *clk_pre, u32 *clk_post)
+{
+       if (!phy)
+               return;
+       if (clk_pre)
+               *clk_pre = phy->timing.clk_pre;
+       if (clk_post)
+               *clk_post = phy->timing.clk_post;
+}
+
index eeed006..6997ec6 100644 (file)
@@ -53,6 +53,23 @@ struct pll_rate {
 
 /* NOTE: keep sorted highest freq to lowest: */
 static const struct pll_rate freqtbl[] = {
+       { 154000000, {
+               { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
+               { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
+               { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
+               { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
+               { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
+               { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
+               { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
+               { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
+               { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
+               { 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
+               { 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
+               { 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
+               { 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
+               { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
+               { 0, 0 } }
+       },
        /* 1080p60/1080p50 case */
        { 148500000, {
                { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
@@ -112,6 +129,23 @@ static const struct pll_rate freqtbl[] = {
                { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
                { 0, 0 } }
        },
+       { 74176000, {
+               { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
+               { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
+               { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
+               { 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
+               { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
+               { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
+               { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
+               { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
+               { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
+               { 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
+               { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
+               { 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
+               { 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
+               { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
+               { 0, 0 } }
+       },
        { 65000000, {
                { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
                { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
index c276624..b9a4ded 100644 (file)
@@ -8,9 +8,9 @@ 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:
-- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml            (  27229 bytes, from 2015-02-10 17:00:41)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml            (  29312 bytes, from 2015-03-23 21:18:48)
 - /local/mnt2/workspace2/sviau/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2014-06-02 18:31:15)
-- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2015-01-23 16:20:19)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2015-03-23 20:38:49)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -37,11 +37,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
 
-enum mdp5_intf {
+enum mdp5_intf_type {
+       INTF_DISABLED = 0,
        INTF_DSI = 1,
        INTF_HDMI = 3,
        INTF_LCDC = 5,
        INTF_eDP = 9,
+       INTF_VIRTUAL = 100,
+       INTF_WB = 101,
 };
 
 enum mdp5_intfnum {
@@ -67,11 +70,11 @@ enum mdp5_pipe {
 
 enum mdp5_ctl_mode {
        MODE_NONE = 0,
-       MODE_ROT0 = 1,
-       MODE_ROT1 = 2,
-       MODE_WB0 = 3,
-       MODE_WB1 = 4,
-       MODE_WFD = 5,
+       MODE_WB_0_BLOCK = 1,
+       MODE_WB_1_BLOCK = 2,
+       MODE_WB_0_LINE = 3,
+       MODE_WB_1_LINE = 4,
+       MODE_WB_2_LINE = 5,
 };
 
 enum mdp5_pack_3d {
@@ -94,33 +97,6 @@ enum mdp5_pipe_bwc {
        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_VIG3_Y = 19,
-       CID_VIG3_CR = 20,
-       CID_VIG3_CB = 21,
-       CID_RGB3 = 22,
-       CID_MAX = 23,
-};
-
 enum mdp5_cursor_format {
        CURSOR_FMT_ARGB8888 = 0,
        CURSOR_FMT_ARGB1555 = 2,
@@ -144,30 +120,25 @@ enum mdp5_data_format {
        DATA_FORMAT_YUV = 1,
 };
 
-#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_WB_0_DONE                                     0x00000001
+#define MDP5_IRQ_WB_1_DONE                                     0x00000002
+#define MDP5_IRQ_WB_2_DONE                                     0x00000010
+#define MDP5_IRQ_PING_PONG_0_DONE                              0x00000100
+#define MDP5_IRQ_PING_PONG_1_DONE                              0x00000200
+#define MDP5_IRQ_PING_PONG_2_DONE                              0x00000400
+#define MDP5_IRQ_PING_PONG_3_DONE                              0x00000800
+#define MDP5_IRQ_PING_PONG_0_RD_PTR                            0x00001000
+#define MDP5_IRQ_PING_PONG_1_RD_PTR                            0x00002000
+#define MDP5_IRQ_PING_PONG_2_RD_PTR                            0x00004000
+#define MDP5_IRQ_PING_PONG_3_RD_PTR                            0x00008000
+#define MDP5_IRQ_PING_PONG_0_WR_PTR                            0x00010000
+#define MDP5_IRQ_PING_PONG_1_WR_PTR                            0x00020000
+#define MDP5_IRQ_PING_PONG_2_WR_PTR                            0x00040000
+#define MDP5_IRQ_PING_PONG_3_WR_PTR                            0x00080000
+#define MDP5_IRQ_PING_PONG_0_AUTO_REF                          0x00100000
+#define MDP5_IRQ_PING_PONG_1_AUTO_REF                          0x00200000
+#define MDP5_IRQ_PING_PONG_2_AUTO_REF                          0x00400000
+#define MDP5_IRQ_PING_PONG_3_AUTO_REF                          0x00800000
 #define MDP5_IRQ_INTF0_UNDER_RUN                               0x01000000
 #define MDP5_IRQ_INTF0_VSYNC                                   0x02000000
 #define MDP5_IRQ_INTF1_UNDER_RUN                               0x04000000
@@ -176,136 +147,186 @@ enum mdp5_data_format {
 #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_MDSS_HW_VERSION                                    0x00000000
+#define MDSS_HW_VERSION_STEP__MASK                             0x0000ffff
+#define MDSS_HW_VERSION_STEP__SHIFT                            0
+static inline uint32_t MDSS_HW_VERSION_STEP(uint32_t val)
+{
+       return ((val) << MDSS_HW_VERSION_STEP__SHIFT) & MDSS_HW_VERSION_STEP__MASK;
+}
+#define MDSS_HW_VERSION_MINOR__MASK                            0x0fff0000
+#define MDSS_HW_VERSION_MINOR__SHIFT                           16
+static inline uint32_t MDSS_HW_VERSION_MINOR(uint32_t val)
+{
+       return ((val) << MDSS_HW_VERSION_MINOR__SHIFT) & MDSS_HW_VERSION_MINOR__MASK;
+}
+#define MDSS_HW_VERSION_MAJOR__MASK                            0xf0000000
+#define MDSS_HW_VERSION_MAJOR__SHIFT                           28
+static inline uint32_t MDSS_HW_VERSION_MAJOR(uint32_t val)
+{
+       return ((val) << MDSS_HW_VERSION_MAJOR__SHIFT) & MDSS_HW_VERSION_MAJOR__MASK;
+}
+
+#define REG_MDSS_HW_INTR_STATUS                                        0x00000010
+#define MDSS_HW_INTR_STATUS_INTR_MDP                           0x00000001
+#define MDSS_HW_INTR_STATUS_INTR_DSI0                          0x00000010
+#define MDSS_HW_INTR_STATUS_INTR_DSI1                          0x00000020
+#define MDSS_HW_INTR_STATUS_INTR_HDMI                          0x00000100
+#define MDSS_HW_INTR_STATUS_INTR_EDP                           0x00001000
 
-#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
+static inline uint32_t __offset_MDP(uint32_t idx)
+{
+       switch (idx) {
+               case 0: return (mdp5_cfg->mdp.base[0]);
+               default: return INVALID_IDX(idx);
+       }
+}
+static inline uint32_t REG_MDP5_MDP(uint32_t i0) { return 0x00000000 + __offset_MDP(i0); }
 
-#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)
+static inline uint32_t REG_MDP5_MDP_HW_VERSION(uint32_t i0) { return 0x00000000 + __offset_MDP(i0); }
+#define MDP5_MDP_HW_VERSION_STEP__MASK                         0x0000ffff
+#define MDP5_MDP_HW_VERSION_STEP__SHIFT                                0
+static inline uint32_t MDP5_MDP_HW_VERSION_STEP(uint32_t val)
 {
-       return ((val) << MDP5_MDP_VERSION_MINOR__SHIFT) & MDP5_MDP_VERSION_MINOR__MASK;
+       return ((val) << MDP5_MDP_HW_VERSION_STEP__SHIFT) & MDP5_MDP_HW_VERSION_STEP__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)
+#define MDP5_MDP_HW_VERSION_MINOR__MASK                                0x0fff0000
+#define MDP5_MDP_HW_VERSION_MINOR__SHIFT                       16
+static inline uint32_t MDP5_MDP_HW_VERSION_MINOR(uint32_t val)
 {
-       return ((val) << MDP5_MDP_VERSION_MAJOR__SHIFT) & MDP5_MDP_VERSION_MAJOR__MASK;
+       return ((val) << MDP5_MDP_HW_VERSION_MINOR__SHIFT) & MDP5_MDP_HW_VERSION_MINOR__MASK;
+}
+#define MDP5_MDP_HW_VERSION_MAJOR__MASK                                0xf0000000
+#define MDP5_MDP_HW_VERSION_MAJOR__SHIFT                       28
+static inline uint32_t MDP5_MDP_HW_VERSION_MAJOR(uint32_t val)
+{
+       return ((val) << MDP5_MDP_HW_VERSION_MAJOR__SHIFT) & MDP5_MDP_HW_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)
+static inline uint32_t REG_MDP5_MDP_DISP_INTF_SEL(uint32_t i0) { return 0x00000004 + __offset_MDP(i0); }
+#define MDP5_MDP_DISP_INTF_SEL_INTF0__MASK                     0x000000ff
+#define MDP5_MDP_DISP_INTF_SEL_INTF0__SHIFT                    0
+static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF0(enum mdp5_intf_type val)
 {
-       return ((val) << MDP5_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_DISP_INTF_SEL_INTF0__MASK;
+       return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_MDP_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)
+#define MDP5_MDP_DISP_INTF_SEL_INTF1__MASK                     0x0000ff00
+#define MDP5_MDP_DISP_INTF_SEL_INTF1__SHIFT                    8
+static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF1(enum mdp5_intf_type val)
 {
-       return ((val) << MDP5_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_DISP_INTF_SEL_INTF1__MASK;
+       return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_MDP_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)
+#define MDP5_MDP_DISP_INTF_SEL_INTF2__MASK                     0x00ff0000
+#define MDP5_MDP_DISP_INTF_SEL_INTF2__SHIFT                    16
+static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF2(enum mdp5_intf_type val)
 {
-       return ((val) << MDP5_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_DISP_INTF_SEL_INTF2__MASK;
+       return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_MDP_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)
+#define MDP5_MDP_DISP_INTF_SEL_INTF3__MASK                     0xff000000
+#define MDP5_MDP_DISP_INTF_SEL_INTF3__SHIFT                    24
+static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF3(enum mdp5_intf_type val)
 {
-       return ((val) << MDP5_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_DISP_INTF_SEL_INTF3__MASK;
+       return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF3__MASK;
 }
 
-#define REG_MDP5_INTR_EN                                       0x00000110
+static inline uint32_t REG_MDP5_MDP_INTR_EN(uint32_t i0) { return 0x00000010 + __offset_MDP(i0); }
 
-#define REG_MDP5_INTR_STATUS                                   0x00000114
+static inline uint32_t REG_MDP5_MDP_INTR_STATUS(uint32_t i0) { return 0x00000014 + __offset_MDP(i0); }
 
-#define REG_MDP5_INTR_CLEAR                                    0x00000118
+static inline uint32_t REG_MDP5_MDP_INTR_CLEAR(uint32_t i0) { return 0x00000018 + __offset_MDP(i0); }
 
-#define REG_MDP5_HIST_INTR_EN                                  0x0000011c
+static inline uint32_t REG_MDP5_MDP_HIST_INTR_EN(uint32_t i0) { return 0x0000001c + __offset_MDP(i0); }
 
-#define REG_MDP5_HIST_INTR_STATUS                              0x00000120
+static inline uint32_t REG_MDP5_MDP_HIST_INTR_STATUS(uint32_t i0) { return 0x00000020 + __offset_MDP(i0); }
 
-#define REG_MDP5_HIST_INTR_CLEAR                               0x00000124
+static inline uint32_t REG_MDP5_MDP_HIST_INTR_CLEAR(uint32_t i0) { return 0x00000024 + __offset_MDP(i0); }
 
-static inline uint32_t REG_MDP5_SMP_ALLOC_W(uint32_t i0) { return 0x00000180 + 0x4*i0; }
+static inline uint32_t REG_MDP5_MDP_SPARE_0(uint32_t i0) { return 0x00000028 + __offset_MDP(i0); }
+#define MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN             0x00000001
 
-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)
+static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_W(uint32_t i0, uint32_t i1) { return 0x00000080 + __offset_MDP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_W_REG(uint32_t i0, uint32_t i1) { return 0x00000080 + __offset_MDP(i0) + 0x4*i1; }
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK                 0x000000ff
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__SHIFT                        0
+static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_MDP_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)
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK                 0x0000ff00
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__SHIFT                        8
+static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_MDP_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)
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK                 0x00ff0000
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__SHIFT                        16
+static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_MDP_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_MDP_SMP_ALLOC_R(uint32_t i0, uint32_t i1) { return 0x00000130 + __offset_MDP(i0) + 0x4*i1; }
 
-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)
+static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_R_REG(uint32_t i0, uint32_t i1) { return 0x00000130 + __offset_MDP(i0) + 0x4*i1; }
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__MASK                 0x000000ff
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__SHIFT                        0
+static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_MDP_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)
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__MASK                 0x0000ff00
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__SHIFT                        8
+static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_MDP_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)
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__MASK                 0x00ff0000
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__SHIFT                        16
+static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_MDP_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;
+               case IGC_VIG: return 0x00000200;
+               case IGC_RGB: return 0x00000210;
+               case IGC_DMA: return 0x00000220;
+               case IGC_DSPP: return 0x00000300;
                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_MDP_IGC(uint32_t i0, enum mdp5_igc_type i1) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1); }
 
-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_MDP_IGC_LUT(uint32_t i0, enum mdp5_igc_type i1, uint32_t i2) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1) + 0x4*i2; }
 
-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)
+static inline uint32_t REG_MDP5_MDP_IGC_LUT_REG(uint32_t i0, enum mdp5_igc_type i1, uint32_t i2) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1) + 0x4*i2; }
+#define MDP5_MDP_IGC_LUT_REG_VAL__MASK                         0x00000fff
+#define MDP5_MDP_IGC_LUT_REG_VAL__SHIFT                                0
+static inline uint32_t MDP5_MDP_IGC_LUT_REG_VAL(uint32_t val)
 {
-       return ((val) << MDP5_IGC_LUT_REG_VAL__SHIFT) & MDP5_IGC_LUT_REG_VAL__MASK;
+       return ((val) << MDP5_MDP_IGC_LUT_REG_VAL__SHIFT) & MDP5_MDP_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
+#define MDP5_MDP_IGC_LUT_REG_INDEX_UPDATE                      0x02000000
+#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_0                    0x10000000
+#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_1                    0x20000000
+#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_2                    0x40000000
+
+#define REG_MDP5_SPLIT_DPL_EN                                  0x000003f4
+
+#define REG_MDP5_SPLIT_DPL_UPPER                               0x000003f8
+#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL                       0x00000002
+#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL_FREE_RUN              0x00000004
+#define MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX                  0x00000010
+#define MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX                  0x00000100
+
+#define REG_MDP5_SPLIT_DPL_LOWER                               0x000004f0
+#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL                       0x00000002
+#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL_FREE_RUN              0x00000004
+#define MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC                     0x00000010
+#define MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC                     0x00000100
 
 static inline uint32_t __offset_CTL(uint32_t idx)
 {
@@ -437,11 +458,19 @@ static inline uint32_t REG_MDP5_CTL_FLUSH(uint32_t i0) { return 0x00000018 + __o
 #define MDP5_CTL_FLUSH_DSPP0                                   0x00002000
 #define MDP5_CTL_FLUSH_DSPP1                                   0x00004000
 #define MDP5_CTL_FLUSH_DSPP2                                   0x00008000
+#define MDP5_CTL_FLUSH_WB                                      0x00010000
 #define MDP5_CTL_FLUSH_CTL                                     0x00020000
 #define MDP5_CTL_FLUSH_VIG3                                    0x00040000
 #define MDP5_CTL_FLUSH_RGB3                                    0x00080000
 #define MDP5_CTL_FLUSH_LM5                                     0x00100000
 #define MDP5_CTL_FLUSH_DSPP3                                   0x00200000
+#define MDP5_CTL_FLUSH_CURSOR_0                                        0x00400000
+#define MDP5_CTL_FLUSH_CURSOR_1                                        0x00800000
+#define MDP5_CTL_FLUSH_CHROMADOWN_0                            0x04000000
+#define MDP5_CTL_FLUSH_TIMING_3                                        0x10000000
+#define MDP5_CTL_FLUSH_TIMING_2                                        0x20000000
+#define MDP5_CTL_FLUSH_TIMING_1                                        0x40000000
+#define MDP5_CTL_FLUSH_TIMING_0                                        0x80000000
 
 static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000001c + __offset_CTL(i0); }
 
@@ -1117,6 +1146,94 @@ static inline uint32_t REG_MDP5_DSPP_GAMUT_BASE(uint32_t i0) { return 0x000002dc
 
 static inline uint32_t REG_MDP5_DSPP_GC_BASE(uint32_t i0) { return 0x000002b0 + __offset_DSPP(i0); }
 
+static inline uint32_t __offset_PP(uint32_t idx)
+{
+       switch (idx) {
+               case 0: return (mdp5_cfg->pp.base[0]);
+               case 1: return (mdp5_cfg->pp.base[1]);
+               case 2: return (mdp5_cfg->pp.base[2]);
+               case 3: return (mdp5_cfg->pp.base[3]);
+               default: return INVALID_IDX(idx);
+       }
+}
+static inline uint32_t REG_MDP5_PP(uint32_t i0) { return 0x00000000 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_TEAR_CHECK_EN(uint32_t i0) { return 0x00000000 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_VSYNC(uint32_t i0) { return 0x00000004 + __offset_PP(i0); }
+#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK                  0x0007ffff
+#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT                 0
+static inline uint32_t MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT) & MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK;
+}
+#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN                   0x00080000
+#define MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN                                0x00100000
+
+static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_HEIGHT(uint32_t i0) { return 0x00000008 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_SYNC_WRCOUNT(uint32_t i0) { return 0x0000000c + __offset_PP(i0); }
+#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK                  0x0000ffff
+#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT                 0
+static inline uint32_t MDP5_PP_SYNC_WRCOUNT_LINE_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK;
+}
+#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK                 0xffff0000
+#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT                        16
+static inline uint32_t MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK;
+}
+
+static inline uint32_t REG_MDP5_PP_VSYNC_INIT_VAL(uint32_t i0) { return 0x00000010 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_INT_COUNT_VAL(uint32_t i0) { return 0x00000014 + __offset_PP(i0); }
+#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK                 0x0000ffff
+#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT                        0
+static inline uint32_t MDP5_PP_INT_COUNT_VAL_LINE_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK;
+}
+#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK                        0xffff0000
+#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT               16
+static inline uint32_t MDP5_PP_INT_COUNT_VAL_FRAME_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK;
+}
+
+static inline uint32_t REG_MDP5_PP_SYNC_THRESH(uint32_t i0) { return 0x00000018 + __offset_PP(i0); }
+#define MDP5_PP_SYNC_THRESH_START__MASK                                0x0000ffff
+#define MDP5_PP_SYNC_THRESH_START__SHIFT                       0
+static inline uint32_t MDP5_PP_SYNC_THRESH_START(uint32_t val)
+{
+       return ((val) << MDP5_PP_SYNC_THRESH_START__SHIFT) & MDP5_PP_SYNC_THRESH_START__MASK;
+}
+#define MDP5_PP_SYNC_THRESH_CONTINUE__MASK                     0xffff0000
+#define MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT                    16
+static inline uint32_t MDP5_PP_SYNC_THRESH_CONTINUE(uint32_t val)
+{
+       return ((val) << MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT) & MDP5_PP_SYNC_THRESH_CONTINUE__MASK;
+}
+
+static inline uint32_t REG_MDP5_PP_START_POS(uint32_t i0) { return 0x0000001c + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_RD_PTR_IRQ(uint32_t i0) { return 0x00000020 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_WR_PTR_IRQ(uint32_t i0) { return 0x00000024 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_OUT_LINE_COUNT(uint32_t i0) { return 0x00000028 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_PP_LINE_COUNT(uint32_t i0) { return 0x0000002c + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_AUTOREFRESH_CONFIG(uint32_t i0) { return 0x00000030 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_FBC_MODE(uint32_t i0) { return 0x00000034 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_FBC_BUDGET_CTL(uint32_t i0) { return 0x00000038 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_FBC_LOSSY_MODE(uint32_t i0) { return 0x0000003c + __offset_PP(i0); }
+
 static inline uint32_t __offset_INTF(uint32_t idx)
 {
        switch (idx) {
index b0a4431..e001e6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,13 +24,23 @@ const struct mdp5_cfg_hw *mdp5_cfg = NULL;
 
 const struct mdp5_cfg_hw msm8x74_config = {
        .name = "msm8x74",
+       .mdp = {
+               .count = 1,
+               .base = { 0x00100 },
+       },
        .smp = {
                .mmb_count = 22,
                .mmb_size = 4096,
+               .clients = {
+                       [SSPP_VIG0] =  1, [SSPP_VIG1] =  4, [SSPP_VIG2] =  7,
+                       [SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
+                       [SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
+               },
        },
        .ctl = {
                .count = 5,
                .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
+               .flush_hw_mask = 0x0003ffff,
        },
        .pipe_vig = {
                .count = 3,
@@ -57,27 +67,49 @@ const struct mdp5_cfg_hw msm8x74_config = {
                .count = 2,
                .base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */
        },
+       .pp = {
+               .count = 3,
+               .base = { 0x12d00, 0x12e00, 0x12f00 },
+       },
        .intf = {
                .count = 4,
                .base = { 0x12500, 0x12700, 0x12900, 0x12b00 },
        },
+       .intfs = {
+               [0] = INTF_eDP,
+               [1] = INTF_DSI,
+               [2] = INTF_DSI,
+               [3] = INTF_HDMI,
+       },
        .max_clk = 200000000,
 };
 
 const struct mdp5_cfg_hw apq8084_config = {
        .name = "apq8084",
+       .mdp = {
+               .count = 1,
+               .base = { 0x00100 },
+       },
        .smp = {
                .mmb_count = 44,
                .mmb_size = 8192,
+               .clients = {
+                       [SSPP_VIG0] =  1, [SSPP_VIG1] =  4,
+                       [SSPP_VIG2] =  7, [SSPP_VIG3] = 19,
+                       [SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
+                       [SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
+                       [SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
+               },
                .reserved_state[0] = GENMASK(7, 0),     /* first 8 MMBs */
-               .reserved[CID_RGB0] = 2,
-               .reserved[CID_RGB1] = 2,
-               .reserved[CID_RGB2] = 2,
-               .reserved[CID_RGB3] = 2,
+               .reserved = {
+                       /* Two SMP blocks are statically tied to RGB pipes: */
+                       [16] = 2, [17] = 2, [18] = 2, [22] = 2,
+               },
        },
        .ctl = {
                .count = 5,
                .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
+               .flush_hw_mask = 0x003fffff,
        },
        .pipe_vig = {
                .count = 4,
@@ -105,10 +137,69 @@ const struct mdp5_cfg_hw apq8084_config = {
                .count = 3,
                .base = { 0x13500, 0x13700, 0x13900 },
        },
+       .pp = {
+               .count = 4,
+               .base = { 0x12f00, 0x13000, 0x13100, 0x13200 },
+       },
        .intf = {
                .count = 5,
                .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 },
        },
+       .intfs = {
+               [0] = INTF_eDP,
+               [1] = INTF_DSI,
+               [2] = INTF_DSI,
+               [3] = INTF_HDMI,
+       },
+       .max_clk = 320000000,
+};
+
+const struct mdp5_cfg_hw msm8x16_config = {
+       .name = "msm8x16",
+       .mdp = {
+               .count = 1,
+               .base = { 0x01000 },
+       },
+       .smp = {
+               .mmb_count = 8,
+               .mmb_size = 8192,
+               .clients = {
+                       [SSPP_VIG0] = 1, [SSPP_DMA0] = 4,
+                       [SSPP_RGB0] = 7, [SSPP_RGB1] = 8,
+               },
+       },
+       .ctl = {
+               .count = 5,
+               .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 },
+               .flush_hw_mask = 0x4003ffff,
+       },
+       .pipe_vig = {
+               .count = 1,
+               .base = { 0x05000 },
+       },
+       .pipe_rgb = {
+               .count = 2,
+               .base = { 0x15000, 0x17000 },
+       },
+       .pipe_dma = {
+               .count = 1,
+               .base = { 0x25000 },
+       },
+       .lm = {
+               .count = 2, /* LM0 and LM3 */
+               .base = { 0x45000, 0x48000 },
+               .nb_stages = 5,
+       },
+       .dspp = {
+               .count = 1,
+               .base = { 0x55000 },
+
+       },
+       .intf = {
+               .count = 1, /* INTF_1 */
+               .base = { 0x6B800 },
+       },
+       /* TODO enable .intfs[] with [1] = INTF_DSI, once DSI is implemented */
        .max_clk = 320000000,
 };
 
@@ -116,6 +207,7 @@ static const struct mdp5_cfg_handler cfg_handlers[] = {
        { .revision = 0, .config = { .hw = &msm8x74_config } },
        { .revision = 2, .config = { .hw = &msm8x74_config } },
        { .revision = 3, .config = { .hw = &apq8084_config } },
+       { .revision = 6, .config = { .hw = &msm8x16_config } },
 };
 
 
index dba4d52..3a551b0 100644 (file)
@@ -44,26 +44,38 @@ struct mdp5_lm_block {
        uint32_t nb_stages;             /* number of stages per blender */
 };
 
+struct mdp5_ctl_block {
+       MDP5_SUB_BLOCK_DEFINITION;
+       uint32_t flush_hw_mask;         /* FLUSH register's hardware mask */
+};
+
 struct mdp5_smp_block {
        int mmb_count;                  /* number of SMP MMBs */
        int mmb_size;                   /* MMB: size in bytes */
+       uint32_t clients[MAX_CLIENTS];  /* SMP port allocation /pipe */
        mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */
        int reserved[MAX_CLIENTS];      /* # of MMBs allocated per client */
 };
 
+#define MDP5_INTF_NUM_MAX      5
+
 struct mdp5_cfg_hw {
        char  *name;
 
+       struct mdp5_sub_block mdp;
        struct mdp5_smp_block smp;
-       struct mdp5_sub_block ctl;
+       struct mdp5_ctl_block ctl;
        struct mdp5_sub_block pipe_vig;
        struct mdp5_sub_block pipe_rgb;
        struct mdp5_sub_block pipe_dma;
        struct mdp5_lm_block  lm;
        struct mdp5_sub_block dspp;
        struct mdp5_sub_block ad;
+       struct mdp5_sub_block pp;
        struct mdp5_sub_block intf;
 
+       u32 intfs[MDP5_INTF_NUM_MAX]; /* array of enum mdp5_intf_type */
+
        uint32_t max_clk;
 };
 
@@ -84,6 +96,10 @@ const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_hn
 struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_hnd);
 int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_hnd);
 
+#define mdp5_cfg_intf_is_virtual(intf_type) ({ \
+       typeof(intf_type) __val = (intf_type);  \
+       (__val) >= INTF_VIRTUAL ? true : false; })
+
 struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
                uint32_t major, uint32_t minor);
 void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_hnd);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
new file mode 100644 (file)
index 0000000..e4e8956
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "mdp5_kms.h"
+
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+struct mdp5_cmd_encoder {
+       struct drm_encoder base;
+       struct mdp5_interface intf;
+       bool enabled;
+       uint32_t bsc;
+};
+#define to_mdp5_cmd_encoder(x) container_of(x, struct mdp5_cmd_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 <linux/msm-bus.h>
+#include <linux/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_cmd_encoder *mdp5_cmd_enc)
+{
+       mdp5_cmd_enc->bsc = msm_bus_scale_register_client(
+                       &mdp_bus_scale_table);
+       DBG("bus scale client: %08x", mdp5_cmd_enc->bsc);
+}
+
+static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc)
+{
+       if (mdp5_cmd_enc->bsc) {
+               msm_bus_scale_unregister_client(mdp5_cmd_enc->bsc);
+               mdp5_cmd_enc->bsc = 0;
+       }
+}
+
+static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx)
+{
+       if (mdp5_cmd_enc->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_cmd_enc->bsc, idx);
+       }
+}
+#else
+static void bs_init(struct mdp5_cmd_encoder *mdp5_cmd_enc) {}
+static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc) {}
+static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx) {}
+#endif
+
+#define VSYNC_CLK_RATE 19200000
+static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
+                                       struct drm_display_mode *mode)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(encoder);
+       struct device *dev = encoder->dev->dev;
+       u32 total_lines_x100, vclks_line, cfg;
+       long vsync_clk_speed;
+       int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
+
+       if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
+               dev_err(dev, "vsync_clk is not initialized\n");
+               return -EINVAL;
+       }
+
+       total_lines_x100 = mode->vtotal * mode->vrefresh;
+       if (!total_lines_x100) {
+               dev_err(dev, "%s: vtotal(%d) or vrefresh(%d) is 0\n",
+                               __func__, mode->vtotal, mode->vrefresh);
+               return -EINVAL;
+       }
+
+       vsync_clk_speed = clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE);
+       if (vsync_clk_speed <= 0) {
+               dev_err(dev, "vsync_clk round rate failed %ld\n",
+                                                       vsync_clk_speed);
+               return -EINVAL;
+       }
+       vclks_line = vsync_clk_speed * 100 / total_lines_x100;
+
+       cfg = MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN
+               | MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN;
+       cfg |= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line);
+
+       mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg);
+       mdp5_write(mdp5_kms,
+               REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), 0xfff0);
+       mdp5_write(mdp5_kms,
+               REG_MDP5_PP_VSYNC_INIT_VAL(pp_id), mode->vdisplay);
+       mdp5_write(mdp5_kms, REG_MDP5_PP_RD_PTR_IRQ(pp_id), mode->vdisplay + 1);
+       mdp5_write(mdp5_kms, REG_MDP5_PP_START_POS(pp_id), mode->vdisplay);
+       mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_THRESH(pp_id),
+                       MDP5_PP_SYNC_THRESH_START(4) |
+                       MDP5_PP_SYNC_THRESH_CONTINUE(4));
+
+       return 0;
+}
+
+static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(encoder);
+       int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
+       int ret;
+
+       ret = clk_set_rate(mdp5_kms->vsync_clk,
+               clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE));
+       if (ret) {
+               dev_err(encoder->dev->dev,
+                       "vsync_clk clk_set_rate failed, %d\n", ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(mdp5_kms->vsync_clk);
+       if (ret) {
+               dev_err(encoder->dev->dev,
+                       "vsync_clk clk_prepare_enable failed, %d\n", ret);
+               return ret;
+       }
+
+       mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1);
+
+       return 0;
+}
+
+static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(encoder);
+       int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0);
+       clk_disable_unprepare(mdp5_kms->vsync_clk);
+}
+
+static void mdp5_cmd_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+       bs_fini(mdp5_cmd_enc);
+       drm_encoder_cleanup(encoder);
+       kfree(mdp5_cmd_enc);
+}
+
+static const struct drm_encoder_funcs mdp5_cmd_encoder_funcs = {
+       .destroy = mdp5_cmd_encoder_destroy,
+};
+
+static bool mdp5_cmd_encoder_mode_fixup(struct drm_encoder *encoder,
+               const struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+
+       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);
+       pingpong_tearcheck_setup(encoder, mode);
+       mdp5_crtc_set_intf(encoder->crtc, &mdp5_cmd_enc->intf);
+}
+
+static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
+{
+       struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+       struct mdp5_kms *mdp5_kms = get_kms(encoder);
+       struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
+       struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
+       int lm = mdp5_crtc_get_lm(encoder->crtc);
+
+       if (WARN_ON(!mdp5_cmd_enc->enabled))
+               return;
+
+       /* Wait for the last frame done */
+       mdp_irq_wait(&mdp5_kms->base, lm2ppdone(lm));
+       pingpong_tearcheck_disable(encoder);
+
+       mdp5_ctl_set_encoder_state(ctl, false);
+       mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
+
+       bs_set(mdp5_cmd_enc, 0);
+
+       mdp5_cmd_enc->enabled = false;
+}
+
+static void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
+{
+       struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+       struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
+       struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
+
+       if (WARN_ON(mdp5_cmd_enc->enabled))
+               return;
+
+       bs_set(mdp5_cmd_enc, 1);
+       if (pingpong_tearcheck_enable(encoder))
+               return;
+
+       mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
+
+       mdp5_ctl_set_encoder_state(ctl, true);
+
+       mdp5_cmd_enc->enabled = true;
+}
+
+static const struct drm_encoder_helper_funcs mdp5_cmd_encoder_helper_funcs = {
+       .mode_fixup = mdp5_cmd_encoder_mode_fixup,
+       .mode_set = mdp5_cmd_encoder_mode_set,
+       .disable = mdp5_cmd_encoder_disable,
+       .enable = mdp5_cmd_encoder_enable,
+};
+
+int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
+                                       struct drm_encoder *slave_encoder)
+{
+       struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+       struct mdp5_kms *mdp5_kms;
+       int intf_num;
+       u32 data = 0;
+
+       if (!encoder || !slave_encoder)
+               return -EINVAL;
+
+       mdp5_kms = get_kms(encoder);
+       intf_num = mdp5_cmd_enc->intf.num;
+
+       /* Switch slave encoder's trigger MUX, to use the master's
+        * start signal for the slave encoder
+        */
+       if (intf_num == 1)
+               data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX;
+       else if (intf_num == 2)
+               data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX;
+       else
+               return -EINVAL;
+
+       /* Smart Panel, Sync mode */
+       data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
+
+       /* Make sure clocks are on when connectors calling this function. */
+       mdp5_enable(mdp5_kms);
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
+
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
+                       MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
+       mdp5_disable(mdp5_kms);
+
+       return 0;
+}
+
+/* initialize command mode encoder */
+struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
+                               struct mdp5_interface *intf)
+{
+       struct drm_encoder *encoder = NULL;
+       struct mdp5_cmd_encoder *mdp5_cmd_enc;
+       int ret;
+
+       if (WARN_ON((intf->type != INTF_DSI) &&
+               (intf->mode != MDP5_INTF_DSI_MODE_COMMAND))) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       mdp5_cmd_enc = kzalloc(sizeof(*mdp5_cmd_enc), GFP_KERNEL);
+       if (!mdp5_cmd_enc) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       memcpy(&mdp5_cmd_enc->intf, intf, sizeof(mdp5_cmd_enc->intf));
+       encoder = &mdp5_cmd_enc->base;
+
+       drm_encoder_init(dev, encoder, &mdp5_cmd_encoder_funcs,
+                       DRM_MODE_ENCODER_DSI);
+
+       drm_encoder_helper_add(encoder, &mdp5_cmd_encoder_helper_funcs);
+
+       bs_init(mdp5_cmd_enc);
+
+       return encoder;
+
+fail:
+       if (encoder)
+               mdp5_cmd_encoder_destroy(encoder);
+
+       return ERR_PTR(ret);
+}
+
index 2f2863c..c153077 100644 (file)
@@ -82,8 +82,6 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending)
        mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank);
 }
 
-#define mdp5_lm_get_flush(lm)  mdp_ctl_flush_mask_lm(lm)
-
 static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
@@ -110,8 +108,8 @@ static void crtc_flush_all(struct drm_crtc *crtc)
        drm_atomic_crtc_for_each_plane(plane, crtc) {
                flush_mask |= mdp5_plane_get_flush(plane);
        }
-       flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
-       flush_mask |= mdp5_lm_get_flush(mdp5_crtc->lm);
+
+       flush_mask |= mdp_ctl_flush_mask_lm(mdp5_crtc->lm);
 
        crtc_flush(crtc, flush_mask);
 }
@@ -298,8 +296,6 @@ static void mdp5_crtc_enable(struct drm_crtc *crtc)
        mdp5_enable(mdp5_kms);
        mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
 
-       crtc_flush_all(crtc);
-
        mdp5_crtc->enabled = true;
 }
 
@@ -444,13 +440,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
-       struct drm_gem_object *cursor_bo, *old_bo;
+       struct drm_gem_object *cursor_bo, *old_bo = NULL;
        uint32_t blendcfg, cursor_addr, stride;
        int ret, bpp, lm;
        unsigned int depth;
        enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
        uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
        uint32_t roi_w, roi_h;
+       bool cursor_enable = true;
        unsigned long flags;
 
        if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
@@ -463,7 +460,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
 
        if (!handle) {
                DBG("Cursor off");
-               return mdp5_ctl_set_cursor(mdp5_crtc->ctl, false);
+               cursor_enable = false;
+               goto set_cursor;
        }
 
        cursor_bo = drm_gem_object_lookup(dev, file, handle);
@@ -504,11 +502,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
 
        spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
 
-       ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true);
-       if (ret)
+set_cursor:
+       ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, 0, cursor_enable);
+       if (ret) {
+               dev_err(dev->dev, "failed to %sable cursor: %d\n",
+                               cursor_enable ? "en" : "dis", ret);
                goto end;
+       }
 
-       flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
        crtc_flush(crtc, flush_mask);
 
 end:
@@ -613,64 +614,39 @@ void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
 }
 
 /* set interface for routing crtc->encoder: */
-void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
-               enum mdp5_intf intf_id)
+void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
-       uint32_t flush_mask = 0;
-       uint32_t intf_sel;
-       unsigned long flags;
+       int lm = mdp5_crtc_get_lm(crtc);
 
        /* now that we know what irq's we want: */
-       mdp5_crtc->err.irqmask = intf2err(intf);
-       mdp5_crtc->vblank.irqmask = intf2vblank(intf);
-       mdp_irq_update(&mdp5_kms->base);
-
-       spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
-       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;
-       }
+       mdp5_crtc->err.irqmask = intf2err(intf->num);
 
-       mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
-       spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
+       /* Register command mode Pingpong done as vblank for now,
+        * so that atomic commit should wait for it to finish.
+        * Ideally, in the future, we should take rd_ptr done as vblank,
+        * and let atomic commit wait for pingpong done for commond mode.
+        */
+       if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+               mdp5_crtc->vblank.irqmask = lm2ppdone(lm);
+       else
+               mdp5_crtc->vblank.irqmask = intf2vblank(lm, intf);
+       mdp_irq_update(&mdp5_kms->base);
 
-       DBG("%s: intf_sel=%08x", mdp5_crtc->name, intf_sel);
        mdp5_ctl_set_intf(mdp5_crtc->ctl, intf);
-       flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
-       flush_mask |= mdp5_lm_get_flush(mdp5_crtc->lm);
-
-       crtc_flush(crtc, flush_mask);
 }
 
 int mdp5_crtc_get_lm(struct drm_crtc *crtc)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       return WARN_ON(!crtc) ? -EINVAL : mdp5_crtc->lm;
+}
 
-       if (WARN_ON(!crtc))
-               return -EINVAL;
-
-       return mdp5_crtc->lm;
+struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       return WARN_ON(!crtc) ? NULL : mdp5_crtc->ctl;
 }
 
 /* initialize crtc */
index 1511290..5488b68 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
  * requested by the client (in mdp5_crtc_mode_set()).
  */
 
+struct op_mode {
+       struct mdp5_interface intf;
+
+       bool encoder_enabled;
+       uint32_t start_mask;
+};
+
 struct mdp5_ctl {
        struct mdp5_ctl_manager *ctlm;
 
        u32 id;
+       int lm;
 
        /* whether this CTL has been allocated or not: */
        bool busy;
 
-       /* memory output connection (@see mdp5_ctl_mode): */
-       u32 mode;
+       /* Operation Mode Configuration for the Pipeline */
+       struct op_mode pipeline;
 
        /* REG_MDP5_CTL_*(<id>) registers access info + lock: */
        spinlock_t hw_lock;
        u32 reg_offset;
 
-       /* flush mask used to commit CTL registers */
-       u32 flush_mask;
+       /* when do CTL registers need to be flushed? (mask of trigger bits) */
+       u32 pending_ctl_trigger;
 
        bool cursor_on;
 
@@ -63,6 +71,9 @@ struct mdp5_ctl_manager {
        u32 nlm;
        u32 nctl;
 
+       /* to filter out non-present bits in the current hardware config */
+       u32 flush_hw_mask;
+
        /* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */
        spinlock_t pool_lock;
        struct mdp5_ctl ctls[MAX_CTL];
@@ -94,31 +105,172 @@ u32 ctl_read(struct mdp5_ctl *ctl, u32 reg)
        return mdp5_read(mdp5_kms, reg);
 }
 
+static void set_display_intf(struct mdp5_kms *mdp5_kms,
+               struct mdp5_interface *intf)
+{
+       unsigned long flags;
+       u32 intf_sel;
+
+       spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
+       intf_sel = mdp5_read(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0));
+
+       switch (intf->num) {
+       case 0:
+               intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF0__MASK;
+               intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF0(intf->type);
+               break;
+       case 1:
+               intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF1__MASK;
+               intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF1(intf->type);
+               break;
+       case 2:
+               intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF2__MASK;
+               intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF2(intf->type);
+               break;
+       case 3:
+               intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF3__MASK;
+               intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF3(intf->type);
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), intf_sel);
+       spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
+}
 
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf)
+static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
 {
        unsigned long flags;
-       static const enum mdp5_intfnum intfnum[] = {
-                       INTF0, INTF1, INTF2, INTF3,
-       };
+       u32 ctl_op = 0;
+
+       if (!mdp5_cfg_intf_is_virtual(intf->type))
+               ctl_op |= MDP5_CTL_OP_INTF_NUM(INTF0 + intf->num);
+
+       switch (intf->type) {
+       case INTF_DSI:
+               if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+                       ctl_op |= MDP5_CTL_OP_CMD_MODE;
+               break;
+
+       case INTF_WB:
+               if (intf->mode == MDP5_INTF_WB_MODE_LINE)
+                       ctl_op |= MDP5_CTL_OP_MODE(MODE_WB_2_LINE);
+               break;
+
+       default:
+               break;
+       }
 
        spin_lock_irqsave(&ctl->hw_lock, flags);
-       ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id),
-                       MDP5_CTL_OP_MODE(ctl->mode) |
-                       MDP5_CTL_OP_INTF_NUM(intfnum[intf]));
+       ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), ctl_op);
        spin_unlock_irqrestore(&ctl->hw_lock, flags);
+}
+
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
+{
+       struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+       struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
+
+       memcpy(&ctl->pipeline.intf, intf, sizeof(*intf));
+
+       ctl->pipeline.start_mask = mdp_ctl_flush_mask_lm(ctl->lm) |
+                                  mdp_ctl_flush_mask_encoder(intf);
+
+       /* Virtual interfaces need not set a display intf (e.g.: Writeback) */
+       if (!mdp5_cfg_intf_is_virtual(intf->type))
+               set_display_intf(mdp5_kms, intf);
+
+       set_ctl_op(ctl, intf);
 
        return 0;
 }
 
-int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable)
+static bool start_signal_needed(struct mdp5_ctl *ctl)
+{
+       struct op_mode *pipeline = &ctl->pipeline;
+
+       if (!pipeline->encoder_enabled || pipeline->start_mask != 0)
+               return false;
+
+       switch (pipeline->intf.type) {
+       case INTF_WB:
+               return true;
+       case INTF_DSI:
+               return pipeline->intf.mode == MDP5_INTF_DSI_MODE_COMMAND;
+       default:
+               return false;
+       }
+}
+
+/*
+ * send_start_signal() - Overlay Processor Start Signal
+ *
+ * For a given control operation (display pipeline), a START signal needs to be
+ * executed in order to kick off operation and activate all layers.
+ * e.g.: DSI command mode, Writeback
+ */
+static void send_start_signal(struct mdp5_ctl *ctl)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctl->hw_lock, flags);
+       ctl_write(ctl, REG_MDP5_CTL_START(ctl->id), 1);
+       spin_unlock_irqrestore(&ctl->hw_lock, flags);
+}
+
+static void refill_start_mask(struct mdp5_ctl *ctl)
+{
+       struct op_mode *pipeline = &ctl->pipeline;
+       struct mdp5_interface *intf = &ctl->pipeline.intf;
+
+       pipeline->start_mask = mdp_ctl_flush_mask_lm(ctl->lm);
+
+       /*
+        * Writeback encoder needs to program & flush
+        * address registers for each page flip..
+        */
+       if (intf->type == INTF_WB)
+               pipeline->start_mask |= mdp_ctl_flush_mask_encoder(intf);
+}
+
+/**
+ * mdp5_ctl_set_encoder_state() - set the encoder state
+ *
+ * @enable: true, when encoder is ready for data streaming; false, otherwise.
+ *
+ * Note:
+ * This encoder state is needed to trigger START signal (data path kickoff).
+ */
+int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled)
+{
+       if (WARN_ON(!ctl))
+               return -EINVAL;
+
+       ctl->pipeline.encoder_enabled = enabled;
+       DBG("intf_%d: %s", ctl->pipeline.intf.num, enabled ? "on" : "off");
+
+       if (start_signal_needed(ctl)) {
+               send_start_signal(ctl);
+               refill_start_mask(ctl);
+       }
+
+       return 0;
+}
+
+/*
+ * Note:
+ * CTL registers need to be flushed after calling this function
+ * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
+ */
+int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable)
 {
        struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
        unsigned long flags;
        u32 blend_cfg;
-       int lm;
+       int lm = ctl->lm;
 
-       lm = mdp5_crtc_get_lm(ctl->crtc);
        if (unlikely(WARN_ON(lm < 0))) {
                dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d",
                                ctl->id, lm);
@@ -138,12 +290,12 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable)
 
        spin_unlock_irqrestore(&ctl->hw_lock, flags);
 
+       ctl->pending_ctl_trigger = mdp_ctl_flush_mask_cursor(cursor_id);
        ctl->cursor_on = enable;
 
        return 0;
 }
 
-
 int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg)
 {
        unsigned long flags;
@@ -157,37 +309,122 @@ int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg)
        ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
        spin_unlock_irqrestore(&ctl->hw_lock, flags);
 
+       ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(lm);
+
        return 0;
 }
 
+u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf)
+{
+       if (intf->type == INTF_WB)
+               return MDP5_CTL_FLUSH_WB;
+
+       switch (intf->num) {
+       case 0: return MDP5_CTL_FLUSH_TIMING_0;
+       case 1: return MDP5_CTL_FLUSH_TIMING_1;
+       case 2: return MDP5_CTL_FLUSH_TIMING_2;
+       case 3: return MDP5_CTL_FLUSH_TIMING_3;
+       default: return 0;
+       }
+}
+
+u32 mdp_ctl_flush_mask_cursor(int cursor_id)
+{
+       switch (cursor_id) {
+       case 0: return MDP5_CTL_FLUSH_CURSOR_0;
+       case 1: return MDP5_CTL_FLUSH_CURSOR_1;
+       default: return 0;
+       }
+}
+
+u32 mdp_ctl_flush_mask_pipe(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;
+       case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3;
+       case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3;
+       default:        return 0;
+       }
+}
+
+u32 mdp_ctl_flush_mask_lm(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;
+       case 5:  return MDP5_CTL_FLUSH_LM5;
+       default: return 0;
+       }
+}
+
+static u32 fix_sw_flush(struct mdp5_ctl *ctl, u32 flush_mask)
+{
+       struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+       u32 sw_mask = 0;
+#define BIT_NEEDS_SW_FIX(bit) \
+       (!(ctl_mgr->flush_hw_mask & bit) && (flush_mask & bit))
+
+       /* for some targets, cursor bit is the same as LM bit */
+       if (BIT_NEEDS_SW_FIX(MDP5_CTL_FLUSH_CURSOR_0))
+               sw_mask |= mdp_ctl_flush_mask_lm(ctl->lm);
+
+       return sw_mask;
+}
+
+/**
+ * mdp5_ctl_commit() - Register Flush
+ *
+ * The flush register is used to indicate several registers are all
+ * programmed, and are safe to update to the back copy of the double
+ * buffered registers.
+ *
+ * Some registers FLUSH bits are shared when the hardware does not have
+ * dedicated bits for them; handling these is the job of fix_sw_flush().
+ *
+ * CTL registers need to be flushed in some circumstances; if that is the
+ * case, some trigger bits will be present in both flush mask and
+ * ctl->pending_ctl_trigger.
+ */
 int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
 {
        struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+       struct op_mode *pipeline = &ctl->pipeline;
        unsigned long flags;
 
-       if (flush_mask & MDP5_CTL_FLUSH_CURSOR_DUMMY) {
-               int lm = mdp5_crtc_get_lm(ctl->crtc);
+       pipeline->start_mask &= ~flush_mask;
 
-               if (unlikely(WARN_ON(lm < 0))) {
-                       dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d",
-                                       ctl->id, lm);
-                       return -EINVAL;
-               }
+       VERB("flush_mask=%x, start_mask=%x, trigger=%x", flush_mask,
+                       pipeline->start_mask, ctl->pending_ctl_trigger);
 
-               /* for current targets, cursor bit is the same as LM bit */
-               flush_mask |= mdp_ctl_flush_mask_lm(lm);
+       if (ctl->pending_ctl_trigger & flush_mask) {
+               flush_mask |= MDP5_CTL_FLUSH_CTL;
+               ctl->pending_ctl_trigger = 0;
        }
 
-       spin_lock_irqsave(&ctl->hw_lock, flags);
-       ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask);
-       spin_unlock_irqrestore(&ctl->hw_lock, flags);
+       flush_mask |= fix_sw_flush(ctl, flush_mask);
 
-       return 0;
-}
+       flush_mask &= ctl_mgr->flush_hw_mask;
 
-u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl)
-{
-       return ctl->flush_mask;
+       if (flush_mask) {
+               spin_lock_irqsave(&ctl->hw_lock, flags);
+               ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask);
+               spin_unlock_irqrestore(&ctl->hw_lock, flags);
+       }
+
+       if (start_signal_needed(ctl)) {
+               send_start_signal(ctl);
+               refill_start_mask(ctl);
+       }
+
+       return 0;
 }
 
 void mdp5_ctl_release(struct mdp5_ctl *ctl)
@@ -208,6 +445,11 @@ void mdp5_ctl_release(struct mdp5_ctl *ctl)
        DBG("CTL %d released", ctl->id);
 }
 
+int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl)
+{
+       return WARN_ON(!ctl) ? -EINVAL : ctl->id;
+}
+
 /*
  * mdp5_ctl_request() - CTL dynamic allocation
  *
@@ -235,8 +477,10 @@ struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr,
 
        ctl = &ctl_mgr->ctls[c];
 
+       ctl->lm = mdp5_crtc_get_lm(crtc);
        ctl->crtc = crtc;
        ctl->busy = true;
+       ctl->pending_ctl_trigger = 0;
        DBG("CTL %d allocated", ctl->id);
 
 unlock:
@@ -267,7 +511,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
                void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg)
 {
        struct mdp5_ctl_manager *ctl_mgr;
-       const struct mdp5_sub_block *ctl_cfg = &hw_cfg->ctl;
+       const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl;
        unsigned long flags;
        int c, ret;
 
@@ -289,6 +533,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
        ctl_mgr->dev = dev;
        ctl_mgr->nlm = hw_cfg->lm.count;
        ctl_mgr->nctl = ctl_cfg->count;
+       ctl_mgr->flush_hw_mask = ctl_cfg->flush_hw_mask;
        spin_lock_init(&ctl_mgr->pool_lock);
 
        /* initialize each CTL of the pool: */
@@ -303,9 +548,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
                }
                ctl->ctlm = ctl_mgr;
                ctl->id = c;
-               ctl->mode = MODE_NONE;
                ctl->reg_offset = ctl_cfg->base[c];
-               ctl->flush_mask = MDP5_CTL_FLUSH_CTL;
                ctl->busy = false;
                spin_lock_init(&ctl->hw_lock);
        }
index ad48788..7a62000 100644 (file)
@@ -33,19 +33,13 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
  * which is then used to call the other mdp5_ctl_*(ctl, ...) functions.
  */
 struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, struct drm_crtc *crtc);
+int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl);
 
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf);
+struct mdp5_interface;
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf);
+int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled);
 
-int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable);
-
-/* @blend_cfg: see LM blender config definition below */
-int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg);
-
-/* @flush_mask: see CTL flush masks definitions below */
-int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask);
-u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl);
-
-void mdp5_ctl_release(struct mdp5_ctl *ctl);
+int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable);
 
 /*
  * blend_cfg (LM blender config):
@@ -72,51 +66,32 @@ static inline u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
 }
 
 /*
- * flush_mask (CTL flush masks):
+ * mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM)
+ *
+ * @blend_cfg: see LM blender config definition below
  *
- * The following functions allow each DRM entity to get and store
- * their own flush mask.
- * Once stored, these masks will then be accessed through each DRM's
- * interface and used by the caller of mdp5_ctl_commit() to specify
- * which block(s) need to be flushed through @flush_mask parameter.
+ * Note:
+ * CTL registers need to be flushed after calling this function
+ * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
  */
+int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg);
 
-#define MDP5_CTL_FLUSH_CURSOR_DUMMY    0x80000000
+/**
+ * mdp_ctl_flush_mask...() - Register FLUSH masks
+ *
+ * These masks are used to specify which block(s) need to be flushed
+ * through @flush_mask parameter in mdp5_ctl_commit(.., flush_mask).
+ */
+u32 mdp_ctl_flush_mask_lm(int lm);
+u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe);
+u32 mdp_ctl_flush_mask_cursor(int cursor_id);
+u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf);
 
-static inline u32 mdp_ctl_flush_mask_cursor(int cursor_id)
-{
-       /* TODO: use id once multiple cursor support is present */
-       (void)cursor_id;
+/* @flush_mask: see CTL flush masks definitions below */
+int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask);
 
-       return MDP5_CTL_FLUSH_CURSOR_DUMMY;
-}
+void mdp5_ctl_release(struct mdp5_ctl *ctl);
 
-static inline u32 mdp_ctl_flush_mask_lm(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;
-       case 5:  return MDP5_CTL_FLUSH_LM5;
-       default: return 0;
-       }
-}
 
-static inline u32 mdp_ctl_flush_mask_pipe(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;
-       case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3;
-       case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3;
-       default:        return 0;
-       }
-}
 
 #endif /* __MDP5_CTL_H__ */
index af0e02f..1188f4b 100644 (file)
@@ -23,8 +23,7 @@
 
 struct mdp5_encoder {
        struct drm_encoder base;
-       int intf;
-       enum mdp5_intf intf_id;
+       struct mdp5_interface intf;
        spinlock_t intf_lock;   /* protect REG_MDP5_INTF_* registers */
        bool enabled;
        uint32_t bsc;
@@ -126,7 +125,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
        struct mdp5_kms *mdp5_kms = get_kms(encoder);
        struct drm_device *dev = encoder->dev;
        struct drm_connector *connector;
-       int intf = mdp5_encoder->intf;
+       int intf = mdp5_encoder->intf.num;
        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;
@@ -188,7 +187,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
         * DISPLAY_V_START = (VBP * HCYCLE) + HBP
         * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
         */
-       if (mdp5_encoder->intf_id == INTF_eDP) {
+       if (mdp5_encoder->intf.type == INTF_eDP) {
                display_v_start += mode->htotal - mode->hsync_start;
                display_v_end -= mode->hsync_start - mode->hdisplay;
        }
@@ -218,21 +217,29 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
        mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3);  /* frame+line? */
 
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+
+       mdp5_crtc_set_intf(encoder->crtc, &mdp5_encoder->intf);
 }
 
 static void mdp5_encoder_disable(struct drm_encoder *encoder)
 {
        struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
        struct mdp5_kms *mdp5_kms = get_kms(encoder);
-       int intf = mdp5_encoder->intf;
+       struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
+       int lm = mdp5_crtc_get_lm(encoder->crtc);
+       struct mdp5_interface *intf = &mdp5_encoder->intf;
+       int intfn = mdp5_encoder->intf.num;
        unsigned long flags;
 
        if (WARN_ON(!mdp5_encoder->enabled))
                return;
 
+       mdp5_ctl_set_encoder_state(ctl, false);
+
        spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
-       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0);
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+       mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
 
        /*
         * Wait for a vsync so we know the ENABLE=0 latched before
@@ -242,7 +249,7 @@ static void mdp5_encoder_disable(struct drm_encoder *encoder)
         * the settings changes for the new modeset (like new
         * scanout buffer) don't latch properly..
         */
-       mdp_irq_wait(&mdp5_kms->base, intf2vblank(intf));
+       mdp_irq_wait(&mdp5_kms->base, intf2vblank(lm, intf));
 
        bs_set(mdp5_encoder, 0);
 
@@ -253,19 +260,21 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
 {
        struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
        struct mdp5_kms *mdp5_kms = get_kms(encoder);
-       int intf = mdp5_encoder->intf;
+       struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
+       struct mdp5_interface *intf = &mdp5_encoder->intf;
+       int intfn = mdp5_encoder->intf.num;
        unsigned long flags;
 
        if (WARN_ON(mdp5_encoder->enabled))
                return;
 
-       mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf,
-                       mdp5_encoder->intf_id);
-
        bs_set(mdp5_encoder, 1);
        spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
-       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1);
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+       mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
+
+       mdp5_ctl_set_encoder_state(ctl, true);
 
        mdp5_encoder->enabled = true;
 }
@@ -277,12 +286,51 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
        .enable = mdp5_encoder_enable,
 };
 
+int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
+                                       struct drm_encoder *slave_encoder)
+{
+       struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+       struct mdp5_kms *mdp5_kms;
+       int intf_num;
+       u32 data = 0;
+
+       if (!encoder || !slave_encoder)
+               return -EINVAL;
+
+       mdp5_kms = get_kms(encoder);
+       intf_num = mdp5_encoder->intf.num;
+
+       /* Switch slave encoder's TimingGen Sync mode,
+        * to use the master's enable signal for the slave encoder.
+        */
+       if (intf_num == 1)
+               data |= MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC;
+       else if (intf_num == 2)
+               data |= MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC;
+       else
+               return -EINVAL;
+
+       /* Make sure clocks are on when connectors calling this function. */
+       mdp5_enable(mdp5_kms);
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0),
+               MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN);
+       /* Dumb Panel, Sync mode */
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0);
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data);
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
+       mdp5_disable(mdp5_kms);
+
+       return 0;
+}
+
 /* initialize encoder */
-struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
-               enum mdp5_intf intf_id)
+struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
+                               struct mdp5_interface *intf)
 {
        struct drm_encoder *encoder = NULL;
        struct mdp5_encoder *mdp5_encoder;
+       int enc_type = (intf->type == INTF_DSI) ?
+               DRM_MODE_ENCODER_DSI : DRM_MODE_ENCODER_TMDS;
        int ret;
 
        mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL);
@@ -291,14 +339,13 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
                goto fail;
        }
 
-       mdp5_encoder->intf = intf;
-       mdp5_encoder->intf_id = intf_id;
+       memcpy(&mdp5_encoder->intf, intf, sizeof(mdp5_encoder->intf));
        encoder = &mdp5_encoder->base;
 
        spin_lock_init(&mdp5_encoder->intf_lock);
 
-       drm_encoder_init(dev, encoder, &mdp5_encoder_funcs,
-                        DRM_MODE_ENCODER_TMDS);
+       drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, enc_type);
+
        drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs);
 
        bs_init(mdp5_encoder);
index a940710..33bd4c6 100644 (file)
@@ -23,7 +23,7 @@
 
 void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask)
 {
-       mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_EN, irqmask);
+       mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_MDP_INTR_EN(0), irqmask);
 }
 
 static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
@@ -35,8 +35,8 @@ void mdp5_irq_preinstall(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
        mdp5_enable(mdp5_kms);
-       mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
-       mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), 0xffffffff);
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_EN(0), 0x00000000);
        mdp5_disable(mdp5_kms);
 }
 
@@ -61,7 +61,7 @@ void mdp5_irq_uninstall(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
        mdp5_enable(mdp5_kms);
-       mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_EN(0), 0x00000000);
        mdp5_disable(mdp5_kms);
 }
 
@@ -73,8 +73,8 @@ static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)
        unsigned int id;
        uint32_t status;
 
-       status = mdp5_read(mdp5_kms, REG_MDP5_INTR_STATUS);
-       mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, status);
+       status = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_STATUS(0));
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), status);
 
        VERB("status=%08x", status);
 
@@ -91,13 +91,13 @@ irqreturn_t mdp5_irq(struct msm_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);
+       intr = mdp5_read(mdp5_kms, REG_MDSS_HW_INTR_STATUS);
 
        VERB("intr=%08x", intr);
 
-       if (intr & MDP5_HW_INTR_STATUS_INTR_MDP) {
+       if (intr & MDSS_HW_INTR_STATUS_INTR_MDP) {
                mdp5_irq_mdp(mdp_kms);
-               intr &= ~MDP5_HW_INTR_STATUS_INTR_MDP;
+               intr &= ~MDSS_HW_INTR_STATUS_INTR_MDP;
        }
 
        while (intr) {
@@ -128,10 +128,10 @@ void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
  * can register to get their irq's delivered
  */
 
-#define VALID_IRQS  (MDP5_HW_INTR_STATUS_INTR_DSI0 | \
-               MDP5_HW_INTR_STATUS_INTR_DSI1 | \
-               MDP5_HW_INTR_STATUS_INTR_HDMI | \
-               MDP5_HW_INTR_STATUS_INTR_EDP)
+#define VALID_IRQS  (MDSS_HW_INTR_STATUS_INTR_DSI0 | \
+               MDSS_HW_INTR_STATUS_INTR_DSI1 | \
+               MDSS_HW_INTR_STATUS_INTR_HDMI | \
+               MDSS_HW_INTR_STATUS_INTR_EDP)
 
 static void mdp5_hw_mask_irq(struct irq_data *irqd)
 {
index 92b61db..dfa8beb 100644 (file)
@@ -58,7 +58,7 @@ static int mdp5_hw_init(struct msm_kms *kms)
         */
 
        spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
-       mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0);
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), 0);
        spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
 
        mdp5_ctlm_hw_reset(mdp5_kms->ctlm);
@@ -86,6 +86,18 @@ static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate,
        return rate;
 }
 
+static int mdp5_set_split_display(struct msm_kms *kms,
+               struct drm_encoder *encoder,
+               struct drm_encoder *slave_encoder,
+               bool is_cmd_mode)
+{
+       if (is_cmd_mode)
+               return mdp5_cmd_encoder_set_split_display(encoder,
+                                                       slave_encoder);
+       else
+               return mdp5_encoder_set_split_display(encoder, slave_encoder);
+}
+
 static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
@@ -131,6 +143,7 @@ static const struct mdp_kms_funcs kms_funcs = {
                .complete_commit = mdp5_complete_commit,
                .get_format      = mdp_get_format,
                .round_pixclk    = mdp5_round_pixclk,
+               .set_split_display = mdp5_set_split_display,
                .preclose        = mdp5_preclose,
                .destroy         = mdp5_destroy,
        },
@@ -161,6 +174,134 @@ int mdp5_enable(struct mdp5_kms *mdp5_kms)
        return 0;
 }
 
+static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
+               enum mdp5_intf_type intf_type, int intf_num,
+               enum mdp5_intf_mode intf_mode)
+{
+       struct drm_device *dev = mdp5_kms->dev;
+       struct msm_drm_private *priv = dev->dev_private;
+       struct drm_encoder *encoder;
+       struct mdp5_interface intf = {
+                       .num    = intf_num,
+                       .type   = intf_type,
+                       .mode   = intf_mode,
+       };
+
+       if ((intf_type == INTF_DSI) &&
+               (intf_mode == MDP5_INTF_DSI_MODE_COMMAND))
+               encoder = mdp5_cmd_encoder_init(dev, &intf);
+       else
+               encoder = mdp5_encoder_init(dev, &intf);
+
+       if (IS_ERR(encoder)) {
+               dev_err(dev->dev, "failed to construct encoder\n");
+               return encoder;
+       }
+
+       encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
+       priv->encoders[priv->num_encoders++] = encoder;
+
+       return encoder;
+}
+
+static int get_dsi_id_from_intf(const struct mdp5_cfg_hw *hw_cfg, int intf_num)
+{
+       const int intf_cnt = hw_cfg->intf.count;
+       const u32 *intfs = hw_cfg->intfs;
+       int id = 0, i;
+
+       for (i = 0; i < intf_cnt; i++) {
+               if (intfs[i] == INTF_DSI) {
+                       if (intf_num == i)
+                               return id;
+
+                       id++;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
+{
+       struct drm_device *dev = mdp5_kms->dev;
+       struct msm_drm_private *priv = dev->dev_private;
+       const struct mdp5_cfg_hw *hw_cfg =
+                                       mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+       enum mdp5_intf_type intf_type = hw_cfg->intfs[intf_num];
+       struct drm_encoder *encoder;
+       int ret = 0;
+
+       switch (intf_type) {
+       case INTF_DISABLED:
+               break;
+       case INTF_eDP:
+               if (!priv->edp)
+                       break;
+
+               encoder = construct_encoder(mdp5_kms, INTF_eDP, intf_num,
+                                       MDP5_INTF_MODE_NONE);
+               if (IS_ERR(encoder)) {
+                       ret = PTR_ERR(encoder);
+                       break;
+               }
+
+               ret = msm_edp_modeset_init(priv->edp, dev, encoder);
+               break;
+       case INTF_HDMI:
+               if (!priv->hdmi)
+                       break;
+
+               encoder = construct_encoder(mdp5_kms, INTF_HDMI, intf_num,
+                                       MDP5_INTF_MODE_NONE);
+               if (IS_ERR(encoder)) {
+                       ret = PTR_ERR(encoder);
+                       break;
+               }
+
+               ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
+               break;
+       case INTF_DSI:
+       {
+               int dsi_id = get_dsi_id_from_intf(hw_cfg, intf_num);
+               struct drm_encoder *dsi_encs[MSM_DSI_ENCODER_NUM];
+               enum mdp5_intf_mode mode;
+               int i;
+
+               if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {
+                       dev_err(dev->dev, "failed to find dsi from intf %d\n",
+                               intf_num);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (!priv->dsi[dsi_id])
+                       break;
+
+               for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
+                       mode = (i == MSM_DSI_CMD_ENCODER_ID) ?
+                               MDP5_INTF_DSI_MODE_COMMAND :
+                               MDP5_INTF_DSI_MODE_VIDEO;
+                       dsi_encs[i] = construct_encoder(mdp5_kms, INTF_DSI,
+                                                       intf_num, mode);
+                       if (IS_ERR(dsi_encs)) {
+                               ret = PTR_ERR(dsi_encs);
+                               break;
+                       }
+               }
+
+               ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, dsi_encs);
+               break;
+       }
+       default:
+               dev_err(dev->dev, "unknown intf: %d\n", intf_type);
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
 static int modeset_init(struct mdp5_kms *mdp5_kms)
 {
        static const enum mdp5_pipe crtcs[] = {
@@ -171,7 +312,6 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
        };
        struct drm_device *dev = mdp5_kms->dev;
        struct msm_drm_private *priv = dev->dev_private;
-       struct drm_encoder *encoder;
        const struct mdp5_cfg_hw *hw_cfg;
        int i, ret;
 
@@ -222,44 +362,13 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
                }
        }
 
-       if (priv->hdmi) {
-               /* 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;
-               }
-
-               encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;;
-               priv->encoders[priv->num_encoders++] = encoder;
-
-               ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
-               if (ret) {
-                       dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
-                       goto fail;
-               }
-       }
-
-       if (priv->edp) {
-               /* Construct encoder for eDP: */
-               encoder = mdp5_encoder_init(dev, 0, INTF_eDP);
-               if (IS_ERR(encoder)) {
-                       dev_err(dev->dev, "failed to construct eDP encoder\n");
-                       ret = PTR_ERR(encoder);
-                       goto fail;
-               }
-
-               encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
-               priv->encoders[priv->num_encoders++] = encoder;
-
-               /* Construct bridge/connector for eDP: */
-               ret = msm_edp_modeset_init(priv->edp, dev, encoder);
-               if (ret) {
-                       dev_err(dev->dev, "failed to initialize eDP: %d\n",
-                                                                       ret);
+       /* Construct encoders and modeset initialize connector devices
+        * for each external display interface.
+        */
+       for (i = 0; i < ARRAY_SIZE(hw_cfg->intfs); i++) {
+               ret = modeset_init_intf(mdp5_kms, i);
+               if (ret)
                        goto fail;
-               }
        }
 
        return 0;
@@ -274,11 +383,11 @@ static void read_hw_revision(struct mdp5_kms *mdp5_kms,
        uint32_t version;
 
        mdp5_enable(mdp5_kms);
-       version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION);
+       version = mdp5_read(mdp5_kms, REG_MDSS_HW_VERSION);
        mdp5_disable(mdp5_kms);
 
-       *major = FIELD(version, MDP5_MDP_VERSION_MAJOR);
-       *minor = FIELD(version, MDP5_MDP_VERSION_MINOR);
+       *major = FIELD(version, MDSS_HW_VERSION_MAJOR);
+       *minor = FIELD(version, MDSS_HW_VERSION_MINOR);
 
        DBG("MDP5 version v%d.%d", *major, *minor);
 }
@@ -321,6 +430,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 
        mdp5_kms->dev = dev;
 
+       /* mdp5_kms->mmio actually represents the MDSS base address */
        mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5");
        if (IS_ERR(mdp5_kms->mmio)) {
                ret = PTR_ERR(mdp5_kms->mmio);
@@ -403,8 +513,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
         * we don't disable):
         */
        mdp5_enable(mdp5_kms);
-       for (i = 0; i < config->hw->intf.count; i++)
+       for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {
+               if (!config->hw->intf.base[i] ||
+                               mdp5_cfg_intf_is_virtual(config->hw->intfs[i]))
+                       continue;
                mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
+       }
        mdp5_disable(mdp5_kms);
        mdelay(16);
 
index 49d011e..2c0de17 100644 (file)
@@ -54,7 +54,7 @@ struct mdp5_kms {
 
        /*
         * lock to protect access to global resources: ie., following register:
-        *      - REG_MDP5_DISP_INTF_SEL
+        *      - REG_MDP5_MDP_DISP_INTF_SEL
         */
        spinlock_t resource_lock;
 
@@ -94,6 +94,24 @@ struct mdp5_plane_state {
 #define to_mdp5_plane_state(x) \
                container_of(x, struct mdp5_plane_state, base)
 
+enum mdp5_intf_mode {
+       MDP5_INTF_MODE_NONE = 0,
+
+       /* Modes used for DSI interface (INTF_DSI type): */
+       MDP5_INTF_DSI_MODE_VIDEO,
+       MDP5_INTF_DSI_MODE_COMMAND,
+
+       /* Modes used for WB interface (INTF_WB type):  */
+       MDP5_INTF_WB_MODE_BLOCK,
+       MDP5_INTF_WB_MODE_LINE,
+};
+
+struct mdp5_interface {
+       int num; /* display interface number */
+       enum mdp5_intf_type type;
+       enum mdp5_intf_mode mode;
+};
+
 static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data)
 {
        msm_writel(data, mdp5_kms->mmio + reg);
@@ -130,9 +148,9 @@ static inline int pipe2nclients(enum mdp5_pipe pipe)
        }
 }
 
-static inline uint32_t intf2err(int intf)
+static inline uint32_t intf2err(int intf_num)
 {
-       switch (intf) {
+       switch (intf_num) {
        case 0:  return MDP5_IRQ_INTF0_UNDER_RUN;
        case 1:  return MDP5_IRQ_INTF1_UNDER_RUN;
        case 2:  return MDP5_IRQ_INTF2_UNDER_RUN;
@@ -141,9 +159,23 @@ static inline uint32_t intf2err(int intf)
        }
 }
 
-static inline uint32_t intf2vblank(int intf)
+#define GET_PING_PONG_ID(layer_mixer)  ((layer_mixer == 5) ? 3 : layer_mixer)
+static inline uint32_t intf2vblank(int lm, struct mdp5_interface *intf)
 {
-       switch (intf) {
+       /*
+        * In case of DSI Command Mode, the Ping Pong's read pointer IRQ
+        * acts as a Vblank signal. The Ping Pong buffer used is bound to
+        * layer mixer.
+        */
+
+       if ((intf->type == INTF_DSI) &&
+                       (intf->mode == MDP5_INTF_DSI_MODE_COMMAND))
+               return MDP5_IRQ_PING_PONG_0_RD_PTR << GET_PING_PONG_ID(lm);
+
+       if (intf->type == INTF_WB)
+               return MDP5_IRQ_WB_2_DONE;
+
+       switch (intf->num) {
        case 0:  return MDP5_IRQ_INTF0_VSYNC;
        case 1:  return MDP5_IRQ_INTF1_VSYNC;
        case 2:  return MDP5_IRQ_INTF2_VSYNC;
@@ -152,6 +184,11 @@ static inline uint32_t intf2vblank(int intf)
        }
 }
 
+static inline uint32_t lm2ppdone(int lm)
+{
+       return MDP5_IRQ_PING_PONG_0_DONE << GET_PING_PONG_ID(lm);
+}
+
 int mdp5_disable(struct mdp5_kms *mdp5_kms);
 int mdp5_enable(struct mdp5_kms *mdp5_kms);
 
@@ -197,13 +234,33 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
 uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
 
 int mdp5_crtc_get_lm(struct drm_crtc *crtc);
+struct mdp5_ctl *mdp5_crtc_get_ctl(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_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf);
 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);
+struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
+               struct mdp5_interface *intf);
+int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
+                                       struct drm_encoder *slave_encoder);
+
+#ifdef CONFIG_DRM_MSM_DSI
+struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
+                               struct mdp5_interface *intf);
+int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
+                                       struct drm_encoder *slave_encoder);
+#else
+static inline struct drm_encoder *mdp5_cmd_encoder_init(
+                       struct drm_device *dev, struct mdp5_interface *intf)
+{
+       return ERR_PTR(-EINVAL);
+}
+static inline int mdp5_cmd_encoder_set_split_display(
+       struct drm_encoder *encoder, struct drm_encoder *slave_encoder)
+{
+       return -EINVAL;
+}
+#endif
 
 #endif /* __MDP5_KMS_H__ */
index 6bd48e2..18a3d20 100644 (file)
@@ -507,8 +507,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
        spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
 
        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_PIPE_SRC_IMG_SIZE_WIDTH(fb->width) |
+                       MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb->height));
 
        mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
                        MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
index 1f795af..16702ae 100644 (file)
@@ -43,7 +43,7 @@
  *     set.
  *
  *  2) mdp5_smp_configure():
- *     As hw is programmed, before FLUSH, MDP5_SMP_ALLOC registers
+ *     As hw is programmed, before FLUSH, MDP5_MDP_SMP_ALLOC registers
  *     are configured for the union(pending, inuse)
  *
  *  3) mdp5_smp_commit():
@@ -74,7 +74,7 @@ struct mdp5_smp {
        spinlock_t state_lock;
        mdp5_smp_state_t state; /* to track smp allocation amongst pipes: */
 
-       struct mdp5_client_smp_state client_state[CID_MAX];
+       struct mdp5_client_smp_state client_state[MAX_CLIENTS];
 };
 
 static inline
@@ -85,27 +85,31 @@ struct mdp5_kms *get_kms(struct mdp5_smp *smp)
        return to_mdp5_kms(to_mdp_kms(priv->kms));
 }
 
-static inline enum mdp5_client_id pipe2client(enum mdp5_pipe pipe, int plane)
+static inline u32 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;
-       case SSPP_VIG3: return CID_VIG3_Y + plane;
-       case SSPP_RGB3: return CID_RGB3;
-       default:        return CID_UNUSED;
-       }
+#define CID_UNUSED     0
+
+       if (WARN_ON(plane >= pipe2nclients(pipe)))
+               return CID_UNUSED;
+
+       /*
+        * Note on SMP clients:
+        * For ViG pipes, fetch Y/Cr/Cb-components clients are always
+        * consecutive, and in that order.
+        *
+        * e.g.:
+        * if mdp5_cfg->smp.clients[SSPP_VIG0] = N,
+        *      Y  plane's client ID is N
+        *      Cr plane's client ID is N + 1
+        *      Cb plane's client ID is N + 2
+        */
+
+       return mdp5_cfg->smp.clients[pipe] + plane;
 }
 
 /* step #1: update # of blocks pending for the client: */
 static int smp_request_block(struct mdp5_smp *smp,
-               enum mdp5_client_id cid, int nblks)
+               u32 cid, int nblks)
 {
        struct mdp5_kms *mdp5_kms = get_kms(smp);
        const struct mdp5_cfg_hw *hw_cfg;
@@ -227,7 +231,7 @@ void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe)
 }
 
 static void update_smp_state(struct mdp5_smp *smp,
-               enum mdp5_client_id cid, mdp5_smp_state_t *assigned)
+               u32 cid, mdp5_smp_state_t *assigned)
 {
        struct mdp5_kms *mdp5_kms = get_kms(smp);
        int cnt = smp->blk_cnt;
@@ -237,25 +241,25 @@ static void update_smp_state(struct mdp5_smp *smp,
                int idx = blk / 3;
                int fld = blk % 3;
 
-               val = mdp5_read(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx));
+               val = mdp5_read(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_W_REG(0, idx));
 
                switch (fld) {
                case 0:
-                       val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
-                       val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid);
+                       val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK;
+                       val |= MDP5_MDP_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);
+                       val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK;
+                       val |= MDP5_MDP_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);
+                       val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK;
+                       val |= MDP5_MDP_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);
+               mdp5_write(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_W_REG(0, idx), val);
+               mdp5_write(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_R_REG(0, idx), val);
        }
 }
 
@@ -267,7 +271,7 @@ void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe)
        int i;
 
        for (i = 0; i < pipe2nclients(pipe); i++) {
-               enum mdp5_client_id cid = pipe2client(pipe, i);
+               u32 cid = pipe2client(pipe, i);
                struct mdp5_client_smp_state *ps = &smp->client_state[cid];
 
                bitmap_or(assigned, ps->inuse, ps->pending, cnt);
@@ -283,7 +287,7 @@ void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
        int i;
 
        for (i = 0; i < pipe2nclients(pipe); i++) {
-               enum mdp5_client_id cid = pipe2client(pipe, i);
+               u32 cid = pipe2client(pipe, i);
                struct mdp5_client_smp_state *ps = &smp->client_state[cid];
 
                /*
index a426911..47f4dd4 100644 (file)
@@ -182,41 +182,57 @@ static int get_mdp_ver(struct platform_device *pdev)
        return 4;
 }
 
-static int msm_load(struct drm_device *dev, unsigned long flags)
-{
-       struct platform_device *pdev = dev->platformdev;
-       struct msm_drm_private *priv;
-       struct msm_kms *kms;
-       int ret;
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               dev_err(dev->dev, "failed to allocate private data\n");
-               return -ENOMEM;
-       }
+#include <linux/of_address.h>
 
-       dev->dev_private = priv;
-
-       priv->wq = alloc_ordered_workqueue("msm", 0);
-       init_waitqueue_head(&priv->fence_event);
-       init_waitqueue_head(&priv->pending_crtcs_event);
-
-       INIT_LIST_HEAD(&priv->inactive_list);
-       INIT_LIST_HEAD(&priv->fence_cbs);
+static int msm_init_vram(struct drm_device *dev)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       unsigned long size = 0;
+       int ret = 0;
 
-       drm_mode_config_init(dev);
+#ifdef CONFIG_OF
+       /* In the device-tree world, we could have a 'memory-region'
+        * phandle, which gives us a link to our "vram".  Allocating
+        * is all nicely abstracted behind the dma api, but we need
+        * to know the entire size to allocate it all in one go. There
+        * are two cases:
+        *  1) device with no IOMMU, in which case we need exclusive
+        *     access to a VRAM carveout big enough for all gpu
+        *     buffers
+        *  2) device with IOMMU, but where the bootloader puts up
+        *     a splash screen.  In this case, the VRAM carveout
+        *     need only be large enough for fbdev fb.  But we need
+        *     exclusive access to the buffer to avoid the kernel
+        *     using those pages for other purposes (which appears
+        *     as corruption on screen before we have a chance to
+        *     load and do initial modeset)
+        */
+       struct device_node *node;
+
+       node = of_parse_phandle(dev->dev->of_node, "memory-region", 0);
+       if (node) {
+               struct resource r;
+               ret = of_address_to_resource(node, 0, &r);
+               if (ret)
+                       return ret;
+               size = r.end - r.start;
+               DRM_INFO("using VRAM carveout: %lx@%08x\n", size, r.start);
+       } else
+#endif
 
        /* 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)) {
+               DRM_INFO("using %s VRAM carveout\n", vram);
+               size = memparse(vram, NULL);
+       }
+
+       if (size) {
                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);
@@ -232,8 +248,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
                if (!p) {
                        dev_err(dev->dev, "failed to allocate VRAM\n");
                        priv->vram.paddr = 0;
-                       ret = -ENOMEM;
-                       goto fail;
+                       return -ENOMEM;
                }
 
                dev_info(dev->dev, "VRAM: %08x->%08x\n",
@@ -241,6 +256,37 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
                                (uint32_t)(priv->vram.paddr + size));
        }
 
+       return ret;
+}
+
+static int msm_load(struct drm_device *dev, unsigned long flags)
+{
+       struct platform_device *pdev = dev->platformdev;
+       struct msm_drm_private *priv;
+       struct msm_kms *kms;
+       int ret;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(dev->dev, "failed to allocate private data\n");
+               return -ENOMEM;
+       }
+
+       dev->dev_private = priv;
+
+       priv->wq = alloc_ordered_workqueue("msm", 0);
+       init_waitqueue_head(&priv->fence_event);
+       init_waitqueue_head(&priv->pending_crtcs_event);
+
+       INIT_LIST_HEAD(&priv->inactive_list);
+       INIT_LIST_HEAD(&priv->fence_cbs);
+
+       drm_mode_config_init(dev);
+
+       ret = msm_init_vram(dev);
+       if (ret)
+               goto fail;
+
        platform_set_drvdata(pdev, dev);
 
        /* Bind all our sub-components: */
@@ -1030,6 +1076,7 @@ static struct platform_driver msm_platform_driver = {
 static int __init msm_drm_register(void)
 {
        DBG("init");
+       msm_dsi_register();
        msm_edp_register();
        hdmi_register();
        adreno_register();
@@ -1043,6 +1090,7 @@ static void __exit msm_drm_unregister(void)
        hdmi_unregister();
        adreno_unregister();
        msm_edp_unregister();
+       msm_dsi_unregister();
 }
 
 module_init(msm_drm_register);
index 9e8d441..04db4bd 100644 (file)
@@ -82,6 +82,9 @@ struct msm_drm_private {
         */
        struct msm_edp *edp;
 
+       /* DSI is shared by mdp4 and mdp5 */
+       struct msm_dsi *dsi[2];
+
        /* when we have more than one 'msm_gpu' these need to be an array: */
        struct msm_gpu *gpu;
        struct msm_file_private *lastctx;
@@ -236,6 +239,32 @@ void __exit msm_edp_unregister(void);
 int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
                struct drm_encoder *encoder);
 
+struct msm_dsi;
+enum msm_dsi_encoder_id {
+       MSM_DSI_VIDEO_ENCODER_ID = 0,
+       MSM_DSI_CMD_ENCODER_ID = 1,
+       MSM_DSI_ENCODER_NUM = 2
+};
+#ifdef CONFIG_DRM_MSM_DSI
+void __init msm_dsi_register(void);
+void __exit msm_dsi_unregister(void);
+int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
+               struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM]);
+#else
+static inline void __init msm_dsi_register(void)
+{
+}
+static inline void __exit msm_dsi_unregister(void)
+{
+}
+static inline int msm_dsi_modeset_init(struct msm_dsi *msm_dsi,
+               struct drm_device *dev,
+               struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
+{
+       return -EINVAL;
+}
+#endif
+
 #ifdef CONFIG_DEBUG_FS
 void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m);
 void msm_gem_describe_objects(struct list_head *list, struct seq_file *m);
index df60f65..95f6532 100644 (file)
@@ -110,7 +110,8 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
        size = mode_cmd.pitches[0] * mode_cmd.height;
        DBG("allocating %d bytes for fb %d", size, dev->primary->index);
        mutex_lock(&dev->struct_mutex);
-       fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
+       fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT |
+                       MSM_BO_WC | MSM_BO_STOLEN);
        mutex_unlock(&dev->struct_mutex);
        if (IS_ERR(fbdev->bo)) {
                ret = PTR_ERR(fbdev->bo);
index 49dea4f..479d8af 100644 (file)
@@ -32,6 +32,12 @@ static dma_addr_t physaddr(struct drm_gem_object *obj)
                        priv->vram.paddr;
 }
 
+static bool use_pages(struct drm_gem_object *obj)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       return !msm_obj->vram_node;
+}
+
 /* allocate pages from VRAM carveout, used when no IOMMU: */
 static struct page **get_pages_vram(struct drm_gem_object *obj,
                int npages)
@@ -72,7 +78,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
                struct page **p;
                int npages = obj->size >> PAGE_SHIFT;
 
-               if (iommu_present(&platform_bus_type))
+               if (use_pages(obj))
                        p = drm_gem_get_pages(obj);
                else
                        p = get_pages_vram(obj, npages);
@@ -116,7 +122,7 @@ static void put_pages(struct drm_gem_object *obj)
                sg_free_table(msm_obj->sgt);
                kfree(msm_obj->sgt);
 
-               if (iommu_present(&platform_bus_type))
+               if (use_pages(obj))
                        drm_gem_put_pages(obj, msm_obj->pages, true, false);
                else {
                        drm_mm_remove_node(msm_obj->vram_node);
@@ -580,6 +586,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;
+       bool use_vram = false;
 
        switch (flags & MSM_BO_CACHE_MASK) {
        case MSM_BO_UNCACHED:
@@ -592,15 +599,23 @@ static int msm_gem_new_impl(struct drm_device *dev,
                return -EINVAL;
        }
 
-       sz = sizeof(*msm_obj);
        if (!iommu_present(&platform_bus_type))
+               use_vram = true;
+       else if ((flags & MSM_BO_STOLEN) && priv->vram.size)
+               use_vram = true;
+
+       if (WARN_ON(use_vram && !priv->vram.size))
+               return -EINVAL;
+
+       sz = sizeof(*msm_obj);
+       if (use_vram)
                sz += sizeof(struct drm_mm_node);
 
        msm_obj = kzalloc(sz, GFP_KERNEL);
        if (!msm_obj)
                return -ENOMEM;
 
-       if (!iommu_present(&platform_bus_type))
+       if (use_vram)
                msm_obj->vram_node = (void *)&msm_obj[1];
 
        msm_obj->flags = flags;
@@ -630,7 +645,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
        if (ret)
                goto fail;
 
-       if (iommu_present(&platform_bus_type)) {
+       if (use_pages(obj)) {
                ret = drm_gem_object_init(dev, obj, size);
                if (ret)
                        goto fail;
index 8fbbd05..85d481e 100644 (file)
@@ -21,6 +21,9 @@
 #include <linux/reservation.h>
 #include "msm_drv.h"
 
+/* Additional internal-use only BO flags: */
+#define MSM_BO_STOLEN        0x10000000    /* try to use stolen/splash memory */
+
 struct msm_gem_object {
        struct drm_gem_object base;
 
@@ -59,7 +62,7 @@ struct msm_gem_object {
        struct reservation_object _resv;
 
        /* For physically contiguous buffers.  Used when we don't have
-        * an IOMMU.
+        * an IOMMU.  Also used for stolen/splashscreen buffer.
         */
        struct drm_mm_node *vram_node;
 };
index 3a78cb4..a9f17bd 100644 (file)
@@ -47,6 +47,10 @@ struct msm_kms_funcs {
        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);
+       int (*set_split_display)(struct msm_kms *kms,
+                       struct drm_encoder *encoder,
+                       struct drm_encoder *slave_encoder,
+                       bool is_cmd_mode);
        /* cleanup: */
        void (*preclose)(struct msm_kms *kms, struct drm_file *file);
        void (*destroy)(struct msm_kms *kms);
index 29bd539..6efa8f3 100644 (file)
@@ -340,11 +340,13 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
 
                /* switch mmio to cpu's native endianness */
 #ifndef __BIG_ENDIAN
-               if (ioread32_native(map + 0x000004) != 0x00000000)
+               if (ioread32_native(map + 0x000004) != 0x00000000) {
 #else
-               if (ioread32_native(map + 0x000004) == 0x00000000)
+               if (ioread32_native(map + 0x000004) == 0x00000000) {
 #endif
                        iowrite32_native(0x01000001, map + 0x000004);
+                       ioread32_native(map);
+               }
 
                /* read boot0 and strapping information */
                boot0 = ioread32_native(map + 0x000000);
index 539561e..108d048 100644 (file)
@@ -142,6 +142,49 @@ gm100_identify(struct nvkm_device *device)
                device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
 #endif
                break;
+       case 0x126:
+               device->cname = "GM206";
+               device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] =  gm204_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gm107_fuse_oclass;
+#if 0
+               /* looks to be some non-trivial changes */
+               device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+               /* priv ring says no to 0x10eb14 writes */
+               device->oclass[NVDEV_SUBDEV_THERM  ] = &gm107_therm_oclass;
+#endif
+               device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm204_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  gm107_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTC    ] =  gm107_ltc_oclass;
+               device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+               device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PMU    ] =  gk208_pmu_oclass;
+#if 0
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  gk208_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  gm107_gr_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DISP   ] =  gm204_disp_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_CE0    ] = &gm204_ce0_oclass;
+               device->oclass[NVDEV_ENGINE_CE1    ] = &gm204_ce1_oclass;
+               device->oclass[NVDEV_ENGINE_CE2    ] = &gm204_ce2_oclass;
+               device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+               device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+               device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+#endif
+               break;
        default:
                nv_fatal(device, "unknown Maxwell chipset\n");
                return -EINVAL;
index b038b6e..043e429 100644 (file)
@@ -502,72 +502,57 @@ nv04_fifo_intr(struct nvkm_subdev *subdev)
 {
        struct nvkm_device *device = nv_device(subdev);
        struct nv04_fifo_priv *priv = (void *)subdev;
-       uint32_t status, reassign;
-       int cnt = 0;
+       u32 mask = nv_rd32(priv, NV03_PFIFO_INTR_EN_0);
+       u32 stat = nv_rd32(priv, NV03_PFIFO_INTR_0) & mask;
+       u32 reassign, chid, get, sem;
 
        reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
-       while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
-               uint32_t chid, get;
-
-               nv_wr32(priv, NV03_PFIFO_CACHES, 0);
-
-               chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
-               get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
+       nv_wr32(priv, NV03_PFIFO_CACHES, 0);
 
-               if (status & NV_PFIFO_INTR_CACHE_ERROR) {
-                       nv04_fifo_cache_error(device, priv, chid, get);
-                       status &= ~NV_PFIFO_INTR_CACHE_ERROR;
-               }
+       chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
+       get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
 
-               if (status & NV_PFIFO_INTR_DMA_PUSHER) {
-                       nv04_fifo_dma_pusher(device, priv, chid);
-                       status &= ~NV_PFIFO_INTR_DMA_PUSHER;
-               }
+       if (stat & NV_PFIFO_INTR_CACHE_ERROR) {
+               nv04_fifo_cache_error(device, priv, chid, get);
+               stat &= ~NV_PFIFO_INTR_CACHE_ERROR;
+       }
 
-               if (status & NV_PFIFO_INTR_SEMAPHORE) {
-                       uint32_t sem;
+       if (stat & NV_PFIFO_INTR_DMA_PUSHER) {
+               nv04_fifo_dma_pusher(device, priv, chid);
+               stat &= ~NV_PFIFO_INTR_DMA_PUSHER;
+       }
 
-                       status &= ~NV_PFIFO_INTR_SEMAPHORE;
-                       nv_wr32(priv, NV03_PFIFO_INTR_0,
-                               NV_PFIFO_INTR_SEMAPHORE);
+       if (stat & NV_PFIFO_INTR_SEMAPHORE) {
+               stat &= ~NV_PFIFO_INTR_SEMAPHORE;
+               nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE);
 
-                       sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
-                       nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
+               sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
+               nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
 
-                       nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
-                       nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-               }
+               nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
+               nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+       }
 
-               if (device->card_type == NV_50) {
-                       if (status & 0x00000010) {
-                               status &= ~0x00000010;
-                               nv_wr32(priv, 0x002100, 0x00000010);
-                       }
-
-                       if (status & 0x40000000) {
-                               nv_wr32(priv, 0x002100, 0x40000000);
-                               nvkm_fifo_uevent(&priv->base);
-                               status &= ~0x40000000;
-                       }
+       if (device->card_type == NV_50) {
+               if (stat & 0x00000010) {
+                       stat &= ~0x00000010;
+                       nv_wr32(priv, 0x002100, 0x00000010);
                }
 
-               if (status) {
-                       nv_warn(priv, "unknown intr 0x%08x, ch %d\n",
-                               status, chid);
-                       nv_wr32(priv, NV03_PFIFO_INTR_0, status);
-                       status = 0;
+               if (stat & 0x40000000) {
+                       nv_wr32(priv, 0x002100, 0x40000000);
+                       nvkm_fifo_uevent(&priv->base);
+                       stat &= ~0x40000000;
                }
-
-               nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
        }
 
-       if (status) {
-               nv_error(priv, "still angry after %d spins, halt\n", cnt);
-               nv_wr32(priv, 0x002140, 0);
-               nv_wr32(priv, 0x000140, 0);
+       if (stat) {
+               nv_warn(priv, "unknown intr 0x%08x\n", stat);
+               nv_mask(priv, NV03_PFIFO_INTR_EN_0, stat, 0x00000000);
+               nv_wr32(priv, NV03_PFIFO_INTR_0, stat);
        }
 
-       nv_wr32(priv, 0x000100, 0x00000100);
+       nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
 }
 
 static int
index 2e7ec38..57e2c5b 100644 (file)
@@ -1032,9 +1032,9 @@ gf100_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418808, 0x00000000, s, b);
-       mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s));
 }
 
 void
index b52300d..5e9454b 100644 (file)
@@ -851,9 +851,9 @@ gk104_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418808, 0x00000000, s, b);
-       mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s));
        mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
 }
 
index 956f4dc..b2fae6e 100644 (file)
@@ -871,9 +871,9 @@ gm107_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418e24, 0x00000000, s, b);
-       mmio_refn(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s));
        mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
 }
 
index d1a89b2..c4e1f08 100644 (file)
@@ -74,7 +74,11 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info)
        u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
        if (ent) {
                if (ver >= 0x41) {
-                       if (!(nv_ro32(bios, ent) & 0x80000000))
+                       u32 ent_value = nv_ro32(bios, ent);
+                       u8 i2c_port = (ent_value >> 27) & 0x1f;
+                       u8 dpaux_port = (ent_value >> 22) & 0x1f;
+                       /* value 0x1f means unused according to DCB 4.x spec */
+                       if (i2c_port == 0x1f && dpaux_port == 0x1f)
                                info->type = DCB_I2C_UNUSED;
                        else
                                info->type = DCB_I2C_PMGR;
index a94b11f..b41965c 100644 (file)
@@ -271,18 +271,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = {
        .best_encoder = omap_connector_attached_encoder,
 };
 
-/* flush an area of the framebuffer (in case of manual update display that
- * is not automatically flushed)
- */
-void omap_connector_flush(struct drm_connector *connector,
-               int x, int y, int w, int h)
-{
-       struct omap_connector *omap_connector = to_omap_connector(connector);
-
-       /* TODO: enable when supported in dss */
-       VERB("%s: %d,%d, %dx%d", omap_connector->dssdev->name, x, y, w, h);
-}
-
 /* initialize connector */
 struct drm_connector *omap_connector_init(struct drm_device *dev,
                int connector_type, struct omap_dss_device *dssdev,
index b0566a1..f456544 100644 (file)
@@ -28,7 +28,6 @@
 
 struct omap_crtc {
        struct drm_crtc base;
-       struct drm_plane *plane;
 
        const char *name;
        int pipe;
@@ -46,7 +45,6 @@ struct omap_crtc {
 
        struct omap_video_timings timings;
        bool enabled;
-       bool full_update;
 
        struct omap_drm_apply apply;
 
@@ -74,8 +72,14 @@ struct omap_crtc {
         * XXX maybe fold into apply_work??
         */
        struct work_struct page_flip_work;
+
+       bool ignore_digit_sync_lost;
 };
 
+/* -----------------------------------------------------------------------------
+ * Helper Functions
+ */
+
 uint32_t pipe2vbl(struct drm_crtc *crtc)
 {
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@@ -83,6 +87,22 @@ uint32_t pipe2vbl(struct drm_crtc *crtc)
        return dispc_mgr_get_vsync_irq(omap_crtc->channel);
 }
 
+const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       return &omap_crtc->timings;
+}
+
+enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       return omap_crtc->channel;
+}
+
+/* -----------------------------------------------------------------------------
+ * DSS Manager Functions
+ */
+
 /*
  * Manager-ops, callbacks from output when they need to configure
  * the upstream part of the video pipe.
@@ -122,7 +142,63 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
 {
 }
 
-static void set_enabled(struct drm_crtc *crtc, bool enable);
+/* Called only from CRTC pre_apply and suspend/resume handlers. */
+static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
+{
+       struct drm_device *dev = crtc->dev;
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       enum omap_channel channel = omap_crtc->channel;
+       struct omap_irq_wait *wait;
+       u32 framedone_irq, vsync_irq;
+       int ret;
+
+       if (dispc_mgr_is_enabled(channel) == enable)
+               return;
+
+       if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
+               /*
+                * Digit output produces some sync lost interrupts during the
+                * first frame when enabling, so we need to ignore those.
+                */
+               omap_crtc->ignore_digit_sync_lost = true;
+       }
+
+       framedone_irq = dispc_mgr_get_framedone_irq(channel);
+       vsync_irq = dispc_mgr_get_vsync_irq(channel);
+
+       if (enable) {
+               wait = omap_irq_wait_init(dev, vsync_irq, 1);
+       } else {
+               /*
+                * When we disable the digit output, we need to wait for
+                * FRAMEDONE to know that DISPC has finished with the output.
+                *
+                * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
+                * that case we need to use vsync interrupt, and wait for both
+                * even and odd frames.
+                */
+
+               if (framedone_irq)
+                       wait = omap_irq_wait_init(dev, framedone_irq, 1);
+               else
+                       wait = omap_irq_wait_init(dev, vsync_irq, 2);
+       }
+
+       dispc_mgr_enable(channel, enable);
+
+       ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
+       if (ret) {
+               dev_err(dev->dev, "%s: timeout waiting for %s\n",
+                               omap_crtc->name, enable ? "enable" : "disable");
+       }
+
+       if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
+               omap_crtc->ignore_digit_sync_lost = false;
+               /* make sure the irq handler sees the value above */
+               mb();
+       }
+}
+
 
 static int omap_crtc_enable(struct omap_overlay_manager *mgr)
 {
@@ -131,7 +207,7 @@ static int omap_crtc_enable(struct omap_overlay_manager *mgr)
        dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
        dispc_mgr_set_timings(omap_crtc->channel,
                        &omap_crtc->timings);
-       set_enabled(&omap_crtc->base, true);
+       omap_crtc_set_enabled(&omap_crtc->base, true);
 
        return 0;
 }
@@ -140,7 +216,7 @@ static void omap_crtc_disable(struct omap_overlay_manager *mgr)
 {
        struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
 
-       set_enabled(&omap_crtc->base, false);
+       omap_crtc_set_enabled(&omap_crtc->base, false);
 }
 
 static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
@@ -149,7 +225,6 @@ static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
        struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
        DBG("%s", omap_crtc->name);
        omap_crtc->timings = *timings;
-       omap_crtc->full_update = true;
 }
 
 static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
@@ -174,19 +249,201 @@ static void omap_crtc_unregister_framedone_handler(
 }
 
 static const struct dss_mgr_ops mgr_ops = {
-               .connect = omap_crtc_connect,
-               .disconnect = omap_crtc_disconnect,
-               .start_update = omap_crtc_start_update,
-               .enable = omap_crtc_enable,
-               .disable = omap_crtc_disable,
-               .set_timings = omap_crtc_set_timings,
-               .set_lcd_config = omap_crtc_set_lcd_config,
-               .register_framedone_handler = omap_crtc_register_framedone_handler,
-               .unregister_framedone_handler = omap_crtc_unregister_framedone_handler,
+       .connect = omap_crtc_connect,
+       .disconnect = omap_crtc_disconnect,
+       .start_update = omap_crtc_start_update,
+       .enable = omap_crtc_enable,
+       .disable = omap_crtc_disable,
+       .set_timings = omap_crtc_set_timings,
+       .set_lcd_config = omap_crtc_set_lcd_config,
+       .register_framedone_handler = omap_crtc_register_framedone_handler,
+       .unregister_framedone_handler = omap_crtc_unregister_framedone_handler,
 };
 
-/*
- * CRTC funcs:
+/* -----------------------------------------------------------------------------
+ * Apply Logic
+ */
+
+static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(irq, struct omap_crtc, error_irq);
+
+       if (omap_crtc->ignore_digit_sync_lost) {
+               irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
+               if (!irqstatus)
+                       return;
+       }
+
+       DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
+}
+
+static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(irq, struct omap_crtc, apply_irq);
+       struct drm_crtc *crtc = &omap_crtc->base;
+
+       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);
+               queue_work(priv->wq, &omap_crtc->apply_work);
+       }
+}
+
+static void apply_worker(struct work_struct *work)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(work, struct omap_crtc, apply_work);
+       struct drm_crtc *crtc = &omap_crtc->base;
+       struct drm_device *dev = crtc->dev;
+       struct omap_drm_apply *apply, *n;
+       bool need_apply;
+
+       /*
+        * Synchronize everything on mode_config.mutex, to keep
+        * the callbacks and list modification all serialized
+        * with respect to modesetting ioctls from userspace.
+        */
+       drm_modeset_lock(&crtc->mutex, NULL);
+       dispc_runtime_get();
+
+       /*
+        * If we are still pending a previous update, wait.. when the
+        * pending update completes, we get kicked again.
+        */
+       if (omap_crtc->apply_irq.registered)
+               goto out;
+
+       /* finish up previous apply's: */
+       list_for_each_entry_safe(apply, n,
+                       &omap_crtc->pending_applies, pending_node) {
+               apply->post_apply(apply);
+               list_del(&apply->pending_node);
+       }
+
+       need_apply = !list_empty(&omap_crtc->queued_applies);
+
+       /* then handle the next round of of queued apply's: */
+       list_for_each_entry_safe(apply, n,
+                       &omap_crtc->queued_applies, queued_node) {
+               apply->pre_apply(apply);
+               list_del(&apply->queued_node);
+               apply->queued = false;
+               list_add_tail(&apply->pending_node,
+                               &omap_crtc->pending_applies);
+       }
+
+       if (need_apply) {
+               enum omap_channel channel = omap_crtc->channel;
+
+               DBG("%s: GO", omap_crtc->name);
+
+               if (dispc_mgr_is_enabled(channel)) {
+                       dispc_mgr_go(channel);
+                       omap_irq_register(dev, &omap_crtc->apply_irq);
+               } else {
+                       struct omap_drm_private *priv = dev->dev_private;
+                       queue_work(priv->wq, &omap_crtc->apply_work);
+               }
+       }
+
+out:
+       dispc_runtime_put();
+       drm_modeset_unlock(&crtc->mutex);
+}
+
+int omap_crtc_apply(struct drm_crtc *crtc,
+               struct omap_drm_apply *apply)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+
+       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
+
+       /* no need to queue it again if it is already queued: */
+       if (apply->queued)
+               return 0;
+
+       apply->queued = true;
+       list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
+
+       /*
+        * If there are no currently pending updates, then go ahead and
+        * kick the worker immediately, otherwise it will run again when
+        * the current update finishes.
+        */
+       if (list_empty(&omap_crtc->pending_applies)) {
+               struct omap_drm_private *priv = crtc->dev->dev_private;
+               queue_work(priv->wq, &omap_crtc->apply_work);
+       }
+
+       return 0;
+}
+
+static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(apply, struct omap_crtc, apply);
+       struct drm_crtc *crtc = &omap_crtc->base;
+       struct omap_drm_private *priv = crtc->dev->dev_private;
+       struct drm_encoder *encoder = NULL;
+       unsigned int i;
+
+       DBG("%s: enabled=%d", omap_crtc->name, omap_crtc->enabled);
+
+       for (i = 0; i < priv->num_encoders; i++) {
+               if (priv->encoders[i]->crtc == crtc) {
+                       encoder = priv->encoders[i];
+                       break;
+               }
+       }
+
+       if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
+               omap_encoder_set_enabled(omap_crtc->current_encoder, false);
+
+       omap_crtc->current_encoder = encoder;
+
+       if (!omap_crtc->enabled) {
+               if (encoder)
+                       omap_encoder_set_enabled(encoder, false);
+       } else {
+               if (encoder) {
+                       omap_encoder_set_enabled(encoder, false);
+                       omap_encoder_update(encoder, omap_crtc->mgr,
+                                       &omap_crtc->timings);
+                       omap_encoder_set_enabled(encoder, true);
+               }
+       }
+}
+
+static void omap_crtc_post_apply(struct omap_drm_apply *apply)
+{
+       /* nothing needed for post-apply */
+}
+
+void omap_crtc_flush(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       int loops = 0;
+
+       while (!list_empty(&omap_crtc->pending_applies) ||
+               !list_empty(&omap_crtc->queued_applies) ||
+               omap_crtc->event || omap_crtc->old_fb) {
+
+               if (++loops > 10) {
+                       dev_err(crtc->dev->dev,
+                               "omap_crtc_flush() timeout\n");
+                       break;
+               }
+
+               schedule_timeout_uninterruptible(msecs_to_jiffies(20));
+       }
+}
+
+/* -----------------------------------------------------------------------------
+ * CRTC Functions
  */
 
 static void omap_crtc_destroy(struct drm_crtc *crtc)
@@ -214,17 +471,13 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
 
        if (enabled != omap_crtc->enabled) {
                omap_crtc->enabled = enabled;
-               omap_crtc->full_update = true;
                omap_crtc_apply(crtc, &omap_crtc->apply);
 
-               /* also enable our private plane: */
-               WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
-
-               /* and any attached overlay planes: */
+               /* Enable/disable all planes associated with the CRTC. */
                for (i = 0; i < priv->num_planes; i++) {
                        struct drm_plane *plane = priv->planes[i];
                        if (plane->crtc == crtc)
-                               WARN_ON(omap_plane_dpms(plane, mode));
+                               WARN_ON(omap_plane_set_enable(plane, enabled));
                }
        }
 }
@@ -256,13 +509,17 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
                        mode->type, mode->flags);
 
        copy_timings_drm_to_omap(&omap_crtc->timings, mode);
-       omap_crtc->full_update = true;
 
-       return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16,
-                       NULL, NULL);
+       /*
+        * The primary plane CRTC can be reset if the plane is disabled directly
+        * through the universal plane API. Set it again here.
+        */
+       crtc->primary->crtc = crtc;
+
+       return omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb,
+                                  0, 0, mode->hdisplay, mode->vdisplay,
+                                  x, y, mode->hdisplay, mode->vdisplay,
+                                  NULL, NULL);
 }
 
 static void omap_crtc_prepare(struct drm_crtc *crtc)
@@ -282,15 +539,13 @@ static void omap_crtc_commit(struct drm_crtc *crtc)
 static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
                struct drm_framebuffer *old_fb)
 {
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       struct drm_plane *plane = omap_crtc->plane;
+       struct drm_plane *plane = crtc->primary;
        struct drm_display_mode *mode = &crtc->mode;
 
        return omap_plane_mode_set(plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16,
-                       NULL, NULL);
+                                  0, 0, mode->hdisplay, mode->vdisplay,
+                                  x, y, mode->hdisplay, mode->vdisplay,
+                                  NULL, NULL);
 }
 
 static void vblank_cb(void *arg)
@@ -299,6 +554,7 @@ static void vblank_cb(void *arg)
        struct drm_device *dev = crtc->dev;
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
        unsigned long flags;
+       struct drm_framebuffer *fb;
 
        spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -306,10 +562,15 @@ static void vblank_cb(void *arg)
        if (omap_crtc->event)
                drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event);
 
+       fb = omap_crtc->old_fb;
+
        omap_crtc->event = NULL;
        omap_crtc->old_fb = NULL;
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       if (fb)
+               drm_framebuffer_unreference(fb);
 }
 
 static void page_flip_worker(struct work_struct *work)
@@ -321,11 +582,10 @@ static void page_flip_worker(struct work_struct *work)
        struct drm_gem_object *bo;
 
        drm_modeset_lock(&crtc->mutex, NULL);
-       omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       crtc->x << 16, crtc->y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16,
-                       vblank_cb, crtc);
+       omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb,
+                           0, 0, mode->hdisplay, mode->vdisplay,
+                           crtc->x, crtc->y, mode->hdisplay, mode->vdisplay,
+                           vblank_cb, crtc);
        drm_modeset_unlock(&crtc->mutex);
 
        bo = omap_framebuffer_bo(crtc->primary->fb, 0);
@@ -361,11 +621,12 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
        if (omap_crtc->old_fb) {
                spin_unlock_irqrestore(&dev->event_lock, flags);
                dev_err(dev->dev, "already a pending flip\n");
-               return -EINVAL;
+               return -EBUSY;
        }
 
        omap_crtc->event = event;
        omap_crtc->old_fb = primary->fb = fb;
+       drm_framebuffer_reference(omap_crtc->old_fb);
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
@@ -385,7 +646,6 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 static int omap_crtc_set_property(struct drm_crtc *crtc,
                struct drm_property *property, uint64_t val)
 {
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
        struct omap_drm_private *priv = crtc->dev->dev_private;
 
        if (property == priv->rotation_prop) {
@@ -393,7 +653,7 @@ static int omap_crtc_set_property(struct drm_crtc *crtc,
                                !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
        }
 
-       return omap_plane_set_property(omap_crtc->plane, property, val);
+       return omap_plane_set_property(crtc->primary, property, val);
 }
 
 static const struct drm_crtc_funcs omap_crtc_funcs = {
@@ -412,256 +672,15 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
        .mode_set_base = omap_crtc_mode_set_base,
 };
 
-const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       return &omap_crtc->timings;
-}
-
-enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       return omap_crtc->channel;
-}
-
-static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(irq, struct omap_crtc, error_irq);
-       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);
-}
-
-static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(irq, struct omap_crtc, apply_irq);
-       struct drm_crtc *crtc = &omap_crtc->base;
-
-       if (!omap_crtc->error_irq.registered)
-               __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);
-               queue_work(priv->wq, &omap_crtc->apply_work);
-       }
-}
-
-static void apply_worker(struct work_struct *work)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(work, struct omap_crtc, apply_work);
-       struct drm_crtc *crtc = &omap_crtc->base;
-       struct drm_device *dev = crtc->dev;
-       struct omap_drm_apply *apply, *n;
-       bool need_apply;
-
-       /*
-        * Synchronize everything on mode_config.mutex, to keep
-        * the callbacks and list modification all serialized
-        * with respect to modesetting ioctls from userspace.
-        */
-       drm_modeset_lock(&crtc->mutex, NULL);
-       dispc_runtime_get();
-
-       /*
-        * If we are still pending a previous update, wait.. when the
-        * pending update completes, we get kicked again.
-        */
-       if (omap_crtc->apply_irq.registered)
-               goto out;
-
-       /* finish up previous apply's: */
-       list_for_each_entry_safe(apply, n,
-                       &omap_crtc->pending_applies, pending_node) {
-               apply->post_apply(apply);
-               list_del(&apply->pending_node);
-       }
-
-       need_apply = !list_empty(&omap_crtc->queued_applies);
-
-       /* then handle the next round of of queued apply's: */
-       list_for_each_entry_safe(apply, n,
-                       &omap_crtc->queued_applies, queued_node) {
-               apply->pre_apply(apply);
-               list_del(&apply->queued_node);
-               apply->queued = false;
-               list_add_tail(&apply->pending_node,
-                               &omap_crtc->pending_applies);
-       }
-
-       if (need_apply) {
-               enum omap_channel channel = omap_crtc->channel;
-
-               DBG("%s: GO", omap_crtc->name);
-
-               if (dispc_mgr_is_enabled(channel)) {
-                       omap_irq_register(dev, &omap_crtc->apply_irq);
-                       dispc_mgr_go(channel);
-               } else {
-                       struct omap_drm_private *priv = dev->dev_private;
-                       queue_work(priv->wq, &omap_crtc->apply_work);
-               }
-       }
-
-out:
-       dispc_runtime_put();
-       drm_modeset_unlock(&crtc->mutex);
-}
-
-int omap_crtc_apply(struct drm_crtc *crtc,
-               struct omap_drm_apply *apply)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-
-       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
-
-       /* no need to queue it again if it is already queued: */
-       if (apply->queued)
-               return 0;
-
-       apply->queued = true;
-       list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
-
-       /*
-        * If there are no currently pending updates, then go ahead and
-        * kick the worker immediately, otherwise it will run again when
-        * the current update finishes.
-        */
-       if (list_empty(&omap_crtc->pending_applies)) {
-               struct omap_drm_private *priv = crtc->dev->dev_private;
-               queue_work(priv->wq, &omap_crtc->apply_work);
-       }
-
-       return 0;
-}
-
-/* called only from apply */
-static void set_enabled(struct drm_crtc *crtc, bool enable)
-{
-       struct drm_device *dev = crtc->dev;
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       enum omap_channel channel = omap_crtc->channel;
-       struct omap_irq_wait *wait;
-       u32 framedone_irq, vsync_irq;
-       int ret;
-
-       if (dispc_mgr_is_enabled(channel) == enable)
-               return;
-
-       /*
-        * Digit output produces some sync lost interrupts during the first
-        * frame when enabling, so we need to ignore those.
-        */
-       omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
-
-       framedone_irq = dispc_mgr_get_framedone_irq(channel);
-       vsync_irq = dispc_mgr_get_vsync_irq(channel);
-
-       if (enable) {
-               wait = omap_irq_wait_init(dev, vsync_irq, 1);
-       } else {
-               /*
-                * When we disable the digit output, we need to wait for
-                * FRAMEDONE to know that DISPC has finished with the output.
-                *
-                * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
-                * that case we need to use vsync interrupt, and wait for both
-                * even and odd frames.
-                */
-
-               if (framedone_irq)
-                       wait = omap_irq_wait_init(dev, framedone_irq, 1);
-               else
-                       wait = omap_irq_wait_init(dev, vsync_irq, 2);
-       }
-
-       dispc_mgr_enable(channel, enable);
-
-       ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
-       if (ret) {
-               dev_err(dev->dev, "%s: timeout waiting for %s\n",
-                               omap_crtc->name, enable ? "enable" : "disable");
-       }
-
-       omap_irq_register(crtc->dev, &omap_crtc->error_irq);
-}
-
-static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(apply, struct omap_crtc, apply);
-       struct drm_crtc *crtc = &omap_crtc->base;
-       struct drm_encoder *encoder = NULL;
-
-       DBG("%s: enabled=%d, full=%d", omap_crtc->name,
-                       omap_crtc->enabled, omap_crtc->full_update);
-
-       if (omap_crtc->full_update) {
-               struct omap_drm_private *priv = crtc->dev->dev_private;
-               int i;
-               for (i = 0; i < priv->num_encoders; i++) {
-                       if (priv->encoders[i]->crtc == crtc) {
-                               encoder = priv->encoders[i];
-                               break;
-                       }
-               }
-       }
-
-       if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
-               omap_encoder_set_enabled(omap_crtc->current_encoder, false);
-
-       omap_crtc->current_encoder = encoder;
-
-       if (!omap_crtc->enabled) {
-               if (encoder)
-                       omap_encoder_set_enabled(encoder, false);
-       } else {
-               if (encoder) {
-                       omap_encoder_set_enabled(encoder, false);
-                       omap_encoder_update(encoder, omap_crtc->mgr,
-                                       &omap_crtc->timings);
-                       omap_encoder_set_enabled(encoder, true);
-               }
-       }
-
-       omap_crtc->full_update = false;
-}
-
-static void omap_crtc_post_apply(struct omap_drm_apply *apply)
-{
-       /* nothing needed for post-apply */
-}
-
-void omap_crtc_flush(struct drm_crtc *crtc)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       int loops = 0;
-
-       while (!list_empty(&omap_crtc->pending_applies) ||
-               !list_empty(&omap_crtc->queued_applies) ||
-               omap_crtc->event || omap_crtc->old_fb) {
-
-               if (++loops > 10) {
-                       dev_err(crtc->dev->dev,
-                               "omap_crtc_flush() timeout\n");
-                       break;
-               }
-
-               schedule_timeout_uninterruptible(msecs_to_jiffies(20));
-       }
-}
+/* -----------------------------------------------------------------------------
+ * Init and Cleanup
+ */
 
 static const char *channel_names[] = {
-               [OMAP_DSS_CHANNEL_LCD] = "lcd",
-               [OMAP_DSS_CHANNEL_DIGIT] = "tv",
-               [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
-               [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
+       [OMAP_DSS_CHANNEL_LCD] = "lcd",
+       [OMAP_DSS_CHANNEL_DIGIT] = "tv",
+       [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
+       [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
 };
 
 void omap_crtc_pre_init(void)
@@ -681,12 +700,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        struct drm_crtc *crtc = NULL;
        struct omap_crtc *omap_crtc;
        struct omap_overlay_manager_info *info;
+       int ret;
 
        DBG("%s", channel_names[channel]);
 
        omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
        if (!omap_crtc)
-               goto fail;
+               return NULL;
 
        crtc = &omap_crtc->base;
 
@@ -700,8 +720,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        omap_crtc->apply.post_apply = omap_crtc_post_apply;
 
        omap_crtc->channel = channel;
-       omap_crtc->plane = plane;
-       omap_crtc->plane->crtc = crtc;
        omap_crtc->name = channel_names[channel];
        omap_crtc->pipe = id;
 
@@ -723,18 +741,18 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
        info->trans_enabled = false;
 
-       drm_crtc_init(dev, crtc, &omap_crtc_funcs);
+       ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
+                                       &omap_crtc_funcs);
+       if (ret < 0) {
+               kfree(omap_crtc);
+               return NULL;
+       }
+
        drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 
-       omap_plane_install_properties(omap_crtc->plane, &crtc->base);
+       omap_plane_install_properties(crtc->primary, &crtc->base);
 
        omap_crtcs[channel] = omap_crtc;
 
        return crtc;
-
-fail:
-       if (crtc)
-               omap_crtc_destroy(crtc);
-
-       return NULL;
 }
index 58bcd6a..9f32a83 100644 (file)
@@ -148,11 +148,15 @@ struct refill_engine {
 
        bool async;
 
-       wait_queue_head_t wait_for_refill;
+       struct completion compl;
 
        struct list_head idle_node;
 };
 
+struct dmm_platform_data {
+       uint32_t cpu_cache_flags;
+};
+
 struct dmm {
        struct device *dev;
        void __iomem *base;
@@ -183,6 +187,8 @@ struct dmm {
 
        /* allocation list and lock */
        struct list_head alloc_head;
+
+       const struct dmm_platform_data *plat_data;
 };
 
 #endif
index 56c6055..042038e 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mm.h>
 #include <linux/time.h>
 #include <linux/list.h>
+#include <linux/completion.h>
 
 #include "omap_dmm_tiler.h"
 #include "omap_dmm_priv.h"
 static struct tcm *containers[TILFMT_NFORMATS];
 static struct dmm *omap_dmm;
 
+#if defined(CONFIG_OF)
+static const struct of_device_id dmm_of_match[];
+#endif
+
 /* global spinlock for protecting lists */
 static DEFINE_SPINLOCK(list_lock);
 
@@ -58,19 +63,19 @@ static const struct {
        uint32_t slot_w;        /* width of each slot (in pixels) */
        uint32_t slot_h;        /* height of each slot (in pixels) */
 } geom[TILFMT_NFORMATS] = {
-               [TILFMT_8BIT]  = GEOM(0, 0, 1),
-               [TILFMT_16BIT] = GEOM(0, 1, 2),
-               [TILFMT_32BIT] = GEOM(1, 1, 4),
-               [TILFMT_PAGE]  = GEOM(SLOT_WIDTH_BITS, SLOT_HEIGHT_BITS, 1),
+       [TILFMT_8BIT]  = GEOM(0, 0, 1),
+       [TILFMT_16BIT] = GEOM(0, 1, 2),
+       [TILFMT_32BIT] = GEOM(1, 1, 4),
+       [TILFMT_PAGE]  = GEOM(SLOT_WIDTH_BITS, SLOT_HEIGHT_BITS, 1),
 };
 
 
 /* lookup table for registers w/ per-engine instances */
 static const uint32_t reg[][4] = {
-               [PAT_STATUS] = {DMM_PAT_STATUS__0, DMM_PAT_STATUS__1,
-                               DMM_PAT_STATUS__2, DMM_PAT_STATUS__3},
-               [PAT_DESCR]  = {DMM_PAT_DESCR__0, DMM_PAT_DESCR__1,
-                               DMM_PAT_DESCR__2, DMM_PAT_DESCR__3},
+       [PAT_STATUS] = {DMM_PAT_STATUS__0, DMM_PAT_STATUS__1,
+                       DMM_PAT_STATUS__2, DMM_PAT_STATUS__3},
+       [PAT_DESCR]  = {DMM_PAT_DESCR__0, DMM_PAT_DESCR__1,
+                       DMM_PAT_DESCR__2, DMM_PAT_DESCR__3},
 };
 
 /* simple allocator to grab next 16 byte aligned memory from txn */
@@ -142,10 +147,10 @@ static irqreturn_t omap_dmm_irq_handler(int irq, void *arg)
 
        for (i = 0; i < dmm->num_engines; i++) {
                if (status & DMM_IRQSTAT_LST) {
-                       wake_up_interruptible(&dmm->engines[i].wait_for_refill);
-
                        if (dmm->engines[i].async)
                                release_engine(&dmm->engines[i]);
+
+                       complete(&dmm->engines[i].compl);
                }
 
                status >>= 8;
@@ -269,15 +274,17 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait)
 
        /* mark whether it is async to denote list management in IRQ handler */
        engine->async = wait ? false : true;
+       reinit_completion(&engine->compl);
+       /* verify that the irq handler sees the 'async' and completion value */
+       smp_mb();
 
        /* kick reload */
        writel(engine->refill_pa,
                dmm->base + reg[PAT_DESCR][engine->id]);
 
        if (wait) {
-               if (wait_event_interruptible_timeout(engine->wait_for_refill,
-                               wait_status(engine, DMM_PATSTATUS_READY) == 0,
-                               msecs_to_jiffies(1)) <= 0) {
+               if (!wait_for_completion_timeout(&engine->compl,
+                               msecs_to_jiffies(1))) {
                        dev_err(dmm->dev, "timed out waiting for done\n");
                        ret = -ETIMEDOUT;
                }
@@ -529,6 +536,11 @@ size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h)
        return round_up(geom[fmt].cpp * w, PAGE_SIZE) * h;
 }
 
+uint32_t tiler_get_cpu_cache_flags(void)
+{
+       return omap_dmm->plat_data->cpu_cache_flags;
+}
+
 bool dmm_is_available(void)
 {
        return omap_dmm ? true : false;
@@ -592,6 +604,18 @@ static int omap_dmm_probe(struct platform_device *dev)
 
        init_waitqueue_head(&omap_dmm->engine_queue);
 
+       if (dev->dev.of_node) {
+               const struct of_device_id *match;
+
+               match = of_match_node(dmm_of_match, dev->dev.of_node);
+               if (!match) {
+                       dev_err(&dev->dev, "failed to find matching device node\n");
+                       return -ENODEV;
+               }
+
+               omap_dmm->plat_data = match->data;
+       }
+
        /* lookup hwmod data - base address and irq */
        mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (!mem) {
@@ -696,7 +720,7 @@ static int omap_dmm_probe(struct platform_device *dev)
                                                (REFILL_BUFFER_SIZE * i);
                omap_dmm->engines[i].refill_pa = omap_dmm->refill_pa +
                                                (REFILL_BUFFER_SIZE * i);
-               init_waitqueue_head(&omap_dmm->engines[i].wait_for_refill);
+               init_completion(&omap_dmm->engines[i].compl);
 
                list_add(&omap_dmm->engines[i].idle_node, &omap_dmm->idle_head);
        }
@@ -941,7 +965,7 @@ error:
 }
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int omap_dmm_resume(struct device *dev)
 {
        struct tcm_area area;
@@ -965,16 +989,28 @@ static int omap_dmm_resume(struct device *dev)
 
        return 0;
 }
-
-static const struct dev_pm_ops omap_dmm_pm_ops = {
-       .resume = omap_dmm_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(omap_dmm_pm_ops, NULL, omap_dmm_resume);
+
 #if defined(CONFIG_OF)
+static const struct dmm_platform_data dmm_omap4_platform_data = {
+       .cpu_cache_flags = OMAP_BO_WC,
+};
+
+static const struct dmm_platform_data dmm_omap5_platform_data = {
+       .cpu_cache_flags = OMAP_BO_UNCACHED,
+};
+
 static const struct of_device_id dmm_of_match[] = {
-       { .compatible = "ti,omap4-dmm", },
-       { .compatible = "ti,omap5-dmm", },
+       {
+               .compatible = "ti,omap4-dmm",
+               .data = &dmm_omap4_platform_data,
+       },
+       {
+               .compatible = "ti,omap5-dmm",
+               .data = &dmm_omap5_platform_data,
+       },
        {},
 };
 #endif
@@ -986,9 +1022,7 @@ struct platform_driver omap_dmm_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 4fdd61e..e83c783 100644 (file)
@@ -106,6 +106,7 @@ uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient);
 size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h);
+uint32_t tiler_get_cpu_cache_flags(void);
 bool dmm_is_available(void);
 
 extern struct platform_driver omap_dmm_driver;
index 8241ed9..94920d4 100644 (file)
@@ -128,6 +128,29 @@ cleanup:
        return r;
 }
 
+static int omap_modeset_create_crtc(struct drm_device *dev, int id,
+                                   enum omap_channel channel)
+{
+       struct omap_drm_private *priv = dev->dev_private;
+       struct drm_plane *plane;
+       struct drm_crtc *crtc;
+
+       plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_PRIMARY);
+       if (IS_ERR(plane))
+               return PTR_ERR(plane);
+
+       crtc = omap_crtc_init(dev, plane, channel, id);
+
+       BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
+       priv->crtcs[id] = crtc;
+       priv->num_crtcs++;
+
+       priv->planes[id] = plane;
+       priv->num_planes++;
+
+       return 0;
+}
+
 static int omap_modeset_init(struct drm_device *dev)
 {
        struct omap_drm_private *priv = dev->dev_private;
@@ -136,6 +159,7 @@ 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 ret;
 
        drm_mode_config_init(dev);
 
@@ -209,18 +233,13 @@ static int omap_modeset_init(struct drm_device *dev)
                 * allocated crtc, we create a new crtc for it
                 */
                if (!channel_used(dev, channel)) {
-                       struct drm_plane *plane;
-                       struct drm_crtc *crtc;
-
-                       plane = omap_plane_init(dev, id, true);
-                       crtc = omap_crtc_init(dev, plane, channel, id);
-
-                       BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
-                       priv->crtcs[id] = crtc;
-                       priv->num_crtcs++;
-
-                       priv->planes[id] = plane;
-                       priv->num_planes++;
+                       ret = omap_modeset_create_crtc(dev, id, channel);
+                       if (ret < 0) {
+                               dev_err(dev->dev,
+                                       "could not create CRTC (channel %u)\n",
+                                       channel);
+                               return ret;
+                       }
 
                        id++;
                }
@@ -234,26 +253,8 @@ static int omap_modeset_init(struct drm_device *dev)
 
                /* find a free manager for this crtc */
                for (i = 0; i < num_mgrs; i++) {
-                       if (!channel_used(dev, i)) {
-                               struct drm_plane *plane;
-                               struct drm_crtc *crtc;
-
-                               plane = omap_plane_init(dev, id, true);
-                               crtc = omap_crtc_init(dev, plane, i, id);
-
-                               BUG_ON(priv->num_crtcs >=
-                                       ARRAY_SIZE(priv->crtcs));
-
-                               priv->crtcs[id] = crtc;
-                               priv->num_crtcs++;
-
-                               priv->planes[id] = plane;
-                               priv->num_planes++;
-
+                       if (!channel_used(dev, i))
                                break;
-                       } else {
-                               continue;
-                       }
                }
 
                if (i == num_mgrs) {
@@ -261,13 +262,24 @@ static int omap_modeset_init(struct drm_device *dev)
                        dev_err(dev->dev, "no managers left for crtc\n");
                        return -ENOMEM;
                }
+
+               ret = omap_modeset_create_crtc(dev, id, i);
+               if (ret < 0) {
+                       dev_err(dev->dev,
+                               "could not create CRTC (channel %u)\n", i);
+                       return ret;
+               }
        }
 
        /*
         * Create normal planes for the remaining overlays:
         */
        for (; id < num_ovls; id++) {
-               struct drm_plane *plane = omap_plane_init(dev, id, false);
+               struct drm_plane *plane;
+
+               plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_OVERLAY);
+               if (IS_ERR(plane))
+                       return PTR_ERR(plane);
 
                BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
                priv->planes[priv->num_planes++] = plane;
@@ -286,14 +298,13 @@ static int omap_modeset_init(struct drm_device *dev)
                for (id = 0; id < priv->num_crtcs; id++) {
                        struct drm_crtc *crtc = priv->crtcs[id];
                        enum omap_channel crtc_channel;
-                       enum omap_dss_output_id supported_outputs;
 
                        crtc_channel = omap_crtc_channel(crtc);
-                       supported_outputs =
-                               dss_feat_get_supported_outputs(crtc_channel);
 
-                       if (supported_outputs & output->id)
+                       if (output->dispc_channel == crtc_channel) {
                                encoder->possible_crtcs |= (1 << id);
+                               break;
+                       }
                }
 
                omap_dss_put_device(output);
@@ -480,6 +491,7 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
 
        priv->wq = alloc_ordered_workqueue("omapdrm", 0);
 
+       spin_lock_init(&priv->list_lock);
        INIT_LIST_HEAD(&priv->obj_list);
 
        omap_gem_init(dev);
@@ -519,7 +531,8 @@ static int dev_unload(struct drm_device *dev)
 
        drm_kms_helper_poll_fini(dev);
 
-       omap_fbdev_free(dev);
+       if (priv->fbdev)
+               omap_fbdev_free(dev);
 
        /* flush crtcs so the fbs get released */
        for (i = 0; i < priv->num_crtcs; i++)
@@ -588,9 +601,11 @@ static void dev_lastclose(struct drm_device *dev)
                }
        }
 
-       ret = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
-       if (ret)
-               DBG("failed to restore crtc mode");
+       if (priv->fbdev) {
+               ret = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
+               if (ret)
+                       DBG("failed to restore crtc mode");
+       }
 }
 
 static void dev_preclose(struct drm_device *dev, struct drm_file *file)
@@ -610,74 +625,57 @@ static const struct vm_operations_struct omap_gem_vm_ops = {
 };
 
 static const struct file_operations omapdriver_fops = {
-               .owner = THIS_MODULE,
-               .open = drm_open,
-               .unlocked_ioctl = drm_ioctl,
-               .release = drm_release,
-               .mmap = omap_gem_mmap,
-               .poll = drm_poll,
-               .read = drm_read,
-               .llseek = noop_llseek,
+       .owner = THIS_MODULE,
+       .open = drm_open,
+       .unlocked_ioctl = drm_ioctl,
+       .release = drm_release,
+       .mmap = omap_gem_mmap,
+       .poll = drm_poll,
+       .read = drm_read,
+       .llseek = noop_llseek,
 };
 
 static struct drm_driver omap_drm_driver = {
-               .driver_features =
-                               DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
-               .load = dev_load,
-               .unload = dev_unload,
-               .open = dev_open,
-               .lastclose = dev_lastclose,
-               .preclose = dev_preclose,
-               .postclose = dev_postclose,
-               .set_busid = drm_platform_set_busid,
-               .get_vblank_counter = drm_vblank_count,
-               .enable_vblank = omap_irq_enable_vblank,
-               .disable_vblank = omap_irq_disable_vblank,
-               .irq_preinstall = omap_irq_preinstall,
-               .irq_postinstall = omap_irq_postinstall,
-               .irq_uninstall = omap_irq_uninstall,
-               .irq_handler = omap_irq_handler,
+       .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM
+                        | DRIVER_PRIME,
+       .load = dev_load,
+       .unload = dev_unload,
+       .open = dev_open,
+       .lastclose = dev_lastclose,
+       .preclose = dev_preclose,
+       .postclose = dev_postclose,
+       .set_busid = drm_platform_set_busid,
+       .get_vblank_counter = drm_vblank_count,
+       .enable_vblank = omap_irq_enable_vblank,
+       .disable_vblank = omap_irq_disable_vblank,
+       .irq_preinstall = omap_irq_preinstall,
+       .irq_postinstall = omap_irq_postinstall,
+       .irq_uninstall = omap_irq_uninstall,
+       .irq_handler = omap_irq_handler,
 #ifdef CONFIG_DEBUG_FS
-               .debugfs_init = omap_debugfs_init,
-               .debugfs_cleanup = omap_debugfs_cleanup,
+       .debugfs_init = omap_debugfs_init,
+       .debugfs_cleanup = omap_debugfs_cleanup,
 #endif
-               .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
-               .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
-               .gem_prime_export = omap_gem_prime_export,
-               .gem_prime_import = omap_gem_prime_import,
-               .gem_free_object = omap_gem_free_object,
-               .gem_vm_ops = &omap_gem_vm_ops,
-               .dumb_create = omap_gem_dumb_create,
-               .dumb_map_offset = omap_gem_dumb_map_offset,
-               .dumb_destroy = drm_gem_dumb_destroy,
-               .ioctls = ioctls,
-               .num_ioctls = DRM_OMAP_NUM_IOCTLS,
-               .fops = &omapdriver_fops,
-               .name = DRIVER_NAME,
-               .desc = DRIVER_DESC,
-               .date = DRIVER_DATE,
-               .major = DRIVER_MAJOR,
-               .minor = DRIVER_MINOR,
-               .patchlevel = DRIVER_PATCHLEVEL,
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export = omap_gem_prime_export,
+       .gem_prime_import = omap_gem_prime_import,
+       .gem_free_object = omap_gem_free_object,
+       .gem_vm_ops = &omap_gem_vm_ops,
+       .dumb_create = omap_gem_dumb_create,
+       .dumb_map_offset = omap_gem_dumb_map_offset,
+       .dumb_destroy = drm_gem_dumb_destroy,
+       .ioctls = ioctls,
+       .num_ioctls = DRM_OMAP_NUM_IOCTLS,
+       .fops = &omapdriver_fops,
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL,
 };
 
-static int pdev_suspend(struct platform_device *pDevice, pm_message_t state)
-{
-       DBG("");
-       return 0;
-}
-
-static int pdev_resume(struct platform_device *device)
-{
-       DBG("");
-       return 0;
-}
-
-static void pdev_shutdown(struct platform_device *device)
-{
-       DBG("");
-}
-
 static int pdev_probe(struct platform_device *device)
 {
        int r;
@@ -709,24 +707,35 @@ static int pdev_remove(struct platform_device *device)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static const struct dev_pm_ops omapdrm_pm_ops = {
-       .resume = omap_gem_resume,
-};
+#ifdef CONFIG_PM_SLEEP
+static int omap_drm_suspend(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+       drm_kms_helper_poll_disable(drm_dev);
+
+       return 0;
+}
+
+static int omap_drm_resume(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+       drm_kms_helper_poll_enable(drm_dev);
+
+       return omap_gem_resume(dev);
+}
 #endif
 
+static SIMPLE_DEV_PM_OPS(omapdrm_pm_ops, omap_drm_suspend, omap_drm_resume);
+
 static struct platform_driver pdev = {
-               .driver = {
-                       .name = DRIVER_NAME,
-#ifdef CONFIG_PM
-                       .pm = &omapdrm_pm_ops,
-#endif
-               },
-               .probe = pdev_probe,
-               .remove = pdev_remove,
-               .suspend = pdev_suspend,
-               .resume = pdev_resume,
-               .shutdown = pdev_shutdown,
+       .driver = {
+               .name = DRIVER_NAME,
+               .pm = &omapdrm_pm_ops,
+       },
+       .probe = pdev_probe,
+       .remove = pdev_remove,
 };
 
 static int __init omap_drm_init(void)
index 60e47b3..b31c79f 100644 (file)
@@ -105,6 +105,9 @@ struct omap_drm_private {
 
        struct workqueue_struct *wq;
 
+       /* lock for obj_list below */
+       spinlock_t list_lock;
+
        /* list of GEM objects: */
        struct list_head obj_list;
 
@@ -160,15 +163,15 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 void omap_crtc_flush(struct drm_crtc *crtc);
 
 struct drm_plane *omap_plane_init(struct drm_device *dev,
-               int plane_id, bool private_plane);
-int omap_plane_dpms(struct drm_plane *plane, int mode);
+               int id, enum drm_plane_type type);
+int omap_plane_set_enable(struct drm_plane *plane, bool enable);
 int omap_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 (*fxn)(void *), void *arg);
+                       struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                       int crtc_x, int crtc_y,
+                       unsigned int crtc_w, unsigned int crtc_h,
+                       unsigned int src_x, unsigned int src_y,
+                       unsigned int src_w, unsigned int src_h,
+                       void (*fxn)(void *), void *arg);
 void omap_plane_install_properties(struct drm_plane *plane,
                struct drm_mode_object *obj);
 int omap_plane_set_property(struct drm_plane *plane,
@@ -186,8 +189,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
                struct drm_encoder *encoder);
 struct drm_encoder *omap_connector_attached_encoder(
                struct drm_connector *connector);
-void omap_connector_flush(struct drm_connector *connector,
-               int x, int y, int w, int h);
 bool omap_connector_get_hdmi_mode(struct drm_connector *connector);
 
 void copy_timings_omap_to_drm(struct drm_display_mode *mode,
@@ -208,8 +209,6 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
                struct omap_drm_window *win, struct omap_overlay_info *info);
 struct drm_connector *omap_framebuffer_get_next_connector(
                struct drm_framebuffer *fb, struct drm_connector *from);
-void omap_framebuffer_flush(struct drm_framebuffer *fb,
-               int x, int y, int w, int h);
 
 void omap_gem_init(struct drm_device *dev);
 void omap_gem_deinit(struct drm_device *dev);
index 2a5cacd..b2c1a29 100644 (file)
@@ -86,6 +86,7 @@ struct plane {
 
 struct omap_framebuffer {
        struct drm_framebuffer base;
+       int pin_count;
        const struct format *format;
        struct plane planes[4];
 };
@@ -121,18 +122,6 @@ static int omap_framebuffer_dirty(struct drm_framebuffer *fb,
                struct drm_file *file_priv, unsigned flags, unsigned color,
                struct drm_clip_rect *clips, unsigned num_clips)
 {
-       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;
 }
 
@@ -261,6 +250,11 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
        int ret, i, n = drm_format_num_planes(fb->pixel_format);
 
+       if (omap_fb->pin_count > 0) {
+               omap_fb->pin_count++;
+               return 0;
+       }
+
        for (i = 0; i < n; i++) {
                struct plane *plane = &omap_fb->planes[i];
                ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true);
@@ -269,6 +263,8 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
                omap_gem_dma_sync(plane->bo, DMA_TO_DEVICE);
        }
 
+       omap_fb->pin_count++;
+
        return 0;
 
 fail:
@@ -287,6 +283,11 @@ int omap_framebuffer_unpin(struct drm_framebuffer *fb)
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
        int ret, i, n = drm_format_num_planes(fb->pixel_format);
 
+       omap_fb->pin_count--;
+
+       if (omap_fb->pin_count > 0)
+               return 0;
+
        for (i = 0; i < n; i++) {
                struct plane *plane = &omap_fb->planes[i];
                ret = omap_gem_put_paddr(plane->bo);
@@ -336,34 +337,6 @@ struct drm_connector *omap_framebuffer_get_next_connector(
        return NULL;
 }
 
-/* flush an area of the framebuffer (in case of manual update display that
- * is not automatically flushed)
- */
-void omap_framebuffer_flush(struct drm_framebuffer *fb,
-               int x, int y, int w, int h)
-{
-       struct drm_connector *connector = NULL;
-
-       VERB("flush: %d,%d %dx%d, fb=%p", x, y, w, h, fb);
-
-       /* FIXME: This is racy - no protection against modeset config changes. */
-       while ((connector = omap_framebuffer_get_next_connector(fb, connector))) {
-               /* only consider connectors that are part of a chain */
-               if (connector->encoder && connector->encoder->crtc) {
-                       /* TODO: maybe this should propagate thru the crtc who
-                        * could do the coordinate translation..
-                        */
-                       struct drm_crtc *crtc = connector->encoder->crtc;
-                       int cx = max(0, x - crtc->x);
-                       int cy = max(0, y - crtc->y);
-                       int cw = w + (x - crtc->x) - cx;
-                       int ch = h + (y - crtc->y) - cy;
-
-                       omap_connector_flush(connector, cx, cy, cw, ch);
-               }
-       }
-}
-
 #ifdef CONFIG_DEBUG_FS
 void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
 {
@@ -407,7 +380,7 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
                struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
 {
-       struct omap_framebuffer *omap_fb;
+       struct omap_framebuffer *omap_fb = NULL;
        struct drm_framebuffer *fb = NULL;
        const struct format *format = NULL;
        int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format);
@@ -450,6 +423,14 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
                        goto fail;
                }
 
+               if (pitch % format->planes[i].stride_bpp != 0) {
+                       dev_err(dev->dev,
+                               "buffer pitch (%d bytes) is not a multiple of pixel size (%d bytes)\n",
+                               pitch, format->planes[i].stride_bpp);
+                       ret = -EINVAL;
+                       goto fail;
+               }
+
                size = pitch * mode_cmd->height / format->planes[i].sub_y;
 
                if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) {
@@ -478,8 +459,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
        return fb;
 
 fail:
-       if (fb)
-               omap_framebuffer_destroy(fb);
+       kfree(omap_fb);
 
        return ERR_PTR(ret);
 }
index d292d24..950cd33 100644 (file)
@@ -42,42 +42,8 @@ struct omap_fbdev {
        struct work_struct work;
 };
 
-static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h);
 static struct drm_fb_helper *get_fb(struct fb_info *fbi);
 
-static ssize_t omap_fbdev_write(struct fb_info *fbi, const char __user *buf,
-               size_t count, loff_t *ppos)
-{
-       ssize_t res;
-
-       res = fb_sys_write(fbi, buf, count, ppos);
-       omap_fbdev_flush(fbi, 0, 0, fbi->var.xres, fbi->var.yres);
-
-       return res;
-}
-
-static void omap_fbdev_fillrect(struct fb_info *fbi,
-               const struct fb_fillrect *rect)
-{
-       sys_fillrect(fbi, rect);
-       omap_fbdev_flush(fbi, rect->dx, rect->dy, rect->width, rect->height);
-}
-
-static void omap_fbdev_copyarea(struct fb_info *fbi,
-               const struct fb_copyarea *area)
-{
-       sys_copyarea(fbi, area);
-       omap_fbdev_flush(fbi, area->dx, area->dy, area->width, area->height);
-}
-
-static void omap_fbdev_imageblit(struct fb_info *fbi,
-               const struct fb_image *image)
-{
-       sys_imageblit(fbi, image);
-       omap_fbdev_flush(fbi, image->dx, image->dy,
-                               image->width, image->height);
-}
-
 static void pan_worker(struct work_struct *work)
 {
        struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work);
@@ -121,10 +87,10 @@ static struct fb_ops omap_fb_ops = {
         * basic fbdev ops which write to the framebuffer
         */
        .fb_read = fb_sys_read,
-       .fb_write = omap_fbdev_write,
-       .fb_fillrect = omap_fbdev_fillrect,
-       .fb_copyarea = omap_fbdev_copyarea,
-       .fb_imageblit = omap_fbdev_imageblit,
+       .fb_write = fb_sys_write,
+       .fb_fillrect = sys_fillrect,
+       .fb_copyarea = sys_copyarea,
+       .fb_imageblit = sys_imageblit,
 
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = drm_fb_helper_set_par,
@@ -294,21 +260,6 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi)
        return fbi->par;
 }
 
-/* flush an area of the framebuffer (in case of manual update display that
- * is not automatically flushed)
- */
-static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h)
-{
-       struct drm_fb_helper *helper = get_fb(fbi);
-
-       if (!helper)
-               return;
-
-       VERB("flush fbdev: %d,%d %dx%d, fbi=%p", x, y, w, h, fbi);
-
-       omap_framebuffer_flush(helper->fb, x, y, w, h);
-}
-
 /* initialize fbdev helper */
 struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev)
 {
index aeb91ed..e9718b9 100644 (file)
@@ -828,6 +828,7 @@ int omap_gem_put_paddr(struct drm_gem_object *obj)
                                dev_err(obj->dev->dev,
                                        "could not release unmap: %d\n", ret);
                        }
+                       omap_obj->paddr = 0;
                        omap_obj->block = NULL;
                }
        }
@@ -1272,13 +1273,16 @@ unlock:
 void omap_gem_free_object(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
+       struct omap_drm_private *priv = dev->dev_private;
        struct omap_gem_object *omap_obj = to_omap_bo(obj);
 
        evict(obj);
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
+       spin_lock(&priv->list_lock);
        list_del(&omap_obj->mm_list);
+       spin_unlock(&priv->list_lock);
 
        drm_gem_free_mmap_offset(obj);
 
@@ -1358,8 +1362,8 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
                /* currently don't allow cached buffers.. there is some caching
                 * stuff that needs to be handled better
                 */
-               flags &= ~(OMAP_BO_CACHED|OMAP_BO_UNCACHED);
-               flags |= OMAP_BO_WC;
+               flags &= ~(OMAP_BO_CACHED|OMAP_BO_WC|OMAP_BO_UNCACHED);
+               flags |= tiler_get_cpu_cache_flags();
 
                /* align dimensions to slot boundaries... */
                tiler_align(gem2fmt(flags),
@@ -1376,7 +1380,9 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
        if (!omap_obj)
                goto fail;
 
+       spin_lock(&priv->list_lock);
        list_add(&omap_obj->mm_list, &priv->obj_list);
+       spin_unlock(&priv->list_lock);
 
        obj = &omap_obj->base;
 
index a2dbfb1..b46dabd 100644 (file)
@@ -156,16 +156,16 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
 }
 
 static struct dma_buf_ops omap_dmabuf_ops = {
-               .map_dma_buf = omap_gem_map_dma_buf,
-               .unmap_dma_buf = omap_gem_unmap_dma_buf,
-               .release = omap_gem_dmabuf_release,
-               .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
-               .end_cpu_access = omap_gem_dmabuf_end_cpu_access,
-               .kmap_atomic = omap_gem_dmabuf_kmap_atomic,
-               .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic,
-               .kmap = omap_gem_dmabuf_kmap,
-               .kunmap = omap_gem_dmabuf_kunmap,
-               .mmap = omap_gem_dmabuf_mmap,
+       .map_dma_buf = omap_gem_map_dma_buf,
+       .unmap_dma_buf = omap_gem_unmap_dma_buf,
+       .release = omap_gem_dmabuf_release,
+       .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
+       .end_cpu_access = omap_gem_dmabuf_end_cpu_access,
+       .kmap_atomic = omap_gem_dmabuf_kmap_atomic,
+       .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic,
+       .kmap = omap_gem_dmabuf_kmap,
+       .kunmap = omap_gem_dmabuf_kunmap,
+       .mmap = omap_gem_dmabuf_mmap,
 };
 
 struct dma_buf *omap_gem_prime_export(struct drm_device *dev,
index f035d2b..3eb097e 100644 (file)
@@ -34,7 +34,7 @@ static void omap_irq_update(struct drm_device *dev)
        struct omap_drm_irq *irq;
        uint32_t irqmask = priv->vblank_mask;
 
-       BUG_ON(!spin_is_locked(&list_lock));
+       assert_spin_locked(&list_lock);
 
        list_for_each_entry(irq, &priv->irq_list, node)
                irqmask |= irq->irqmask;
index ee8e2b3..1c6b63f 100644 (file)
@@ -65,12 +65,16 @@ struct omap_plane {
        struct callback apply_done_cb;
 };
 
-static void unpin_worker(struct drm_flip_work *work, void *val)
+static void omap_plane_unpin_worker(struct drm_flip_work *work, void *val)
 {
        struct omap_plane *omap_plane =
                        container_of(work, struct omap_plane, unpin_work);
        struct drm_device *dev = omap_plane->base.dev;
 
+       /*
+        * omap_framebuffer_pin/unpin are always called from priv->wq,
+        * so there's no need for locking here.
+        */
        omap_framebuffer_unpin(val);
        mutex_lock(&dev->mode_config.mutex);
        drm_framebuffer_unreference(val);
@@ -78,7 +82,8 @@ static void unpin_worker(struct drm_flip_work *work, void *val)
 }
 
 /* update which fb (if any) is pinned for scanout */
-static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
+static int omap_plane_update_pin(struct drm_plane *plane,
+                                struct drm_framebuffer *fb)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
        struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb;
@@ -121,13 +126,12 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
        struct drm_crtc *crtc = plane->crtc;
        enum omap_channel channel;
        bool enabled = omap_plane->enabled && crtc;
-       bool ilace, replication;
        int ret;
 
        DBG("%s, enabled=%d", omap_plane->name, enabled);
 
        /* if fb has changed, pin new fb: */
-       update_pin(plane, enabled ? plane->fb : NULL);
+       omap_plane_update_pin(plane, enabled ? plane->fb : NULL);
 
        if (!enabled) {
                dispc_ovl_enable(omap_plane->id, false);
@@ -145,20 +149,17 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
        DBG("%d,%d %pad %pad", info->pos_x, info->pos_y,
                        &info->paddr, &info->p_uv_addr);
 
-       /* TODO: */
-       ilace = false;
-       replication = false;
+       dispc_ovl_set_channel_out(omap_plane->id, channel);
 
        /* and finally, update omapdss: */
-       ret = dispc_ovl_setup(omap_plane->id, info,
-                       replication, omap_crtc_timings(crtc), false);
+       ret = dispc_ovl_setup(omap_plane->id, info, false,
+                             omap_crtc_timings(crtc), false);
        if (ret) {
                dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
                return;
        }
 
        dispc_ovl_enable(omap_plane->id, true);
-       dispc_ovl_set_channel_out(omap_plane->id, channel);
 }
 
 static void omap_plane_post_apply(struct omap_drm_apply *apply)
@@ -167,7 +168,6 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
                        container_of(apply, struct omap_plane, apply);
        struct drm_plane *plane = &omap_plane->base;
        struct omap_drm_private *priv = plane->dev->dev_private;
-       struct omap_overlay_info *info = &omap_plane->info;
        struct callback cb;
 
        cb = omap_plane->apply_done_cb;
@@ -177,14 +177,9 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
 
        if (cb.fxn)
                cb.fxn(cb.arg);
-
-       if (omap_plane->enabled) {
-               omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
-                               info->out_width, info->out_height);
-       }
 }
 
-static int apply(struct drm_plane *plane)
+static int omap_plane_apply(struct drm_plane *plane)
 {
        if (plane->crtc) {
                struct omap_plane *omap_plane = to_omap_plane(plane);
@@ -194,12 +189,12 @@ static int apply(struct drm_plane *plane)
 }
 
 int omap_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 (*fxn)(void *), void *arg)
+                       struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                       int crtc_x, int crtc_y,
+                       unsigned int crtc_w, unsigned int crtc_h,
+                       unsigned int src_x, unsigned int src_y,
+                       unsigned int src_w, unsigned int src_h,
+                       void (*fxn)(void *), void *arg)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
        struct omap_drm_window *win = &omap_plane->win;
@@ -209,11 +204,10 @@ int omap_plane_mode_set(struct drm_plane *plane,
        win->crtc_w = crtc_w;
        win->crtc_h = crtc_h;
 
-       /* src values are in Q16 fixed point, convert to integer: */
-       win->src_x = src_x >> 16;
-       win->src_y = src_y >> 16;
-       win->src_w = src_w >> 16;
-       win->src_h = src_h >> 16;
+       win->src_x = src_x;
+       win->src_y = src_y;
+       win->src_w = src_w;
+       win->src_h = src_h;
 
        if (fxn) {
                /* omap_crtc should ensure that a new page flip
@@ -225,15 +219,7 @@ int omap_plane_mode_set(struct drm_plane *plane,
                omap_plane->apply_done_cb.arg = arg;
        }
 
-       if (plane->fb)
-               drm_framebuffer_unreference(plane->fb);
-
-       drm_framebuffer_reference(fb);
-
-       plane->fb = fb;
-       plane->crtc = crtc;
-
-       return apply(plane);
+       return omap_plane_apply(plane);
 }
 
 static int omap_plane_update(struct drm_plane *plane,
@@ -254,17 +240,29 @@ static int omap_plane_update(struct drm_plane *plane,
                break;
        }
 
+       /*
+        * We don't need to take a reference to the framebuffer as the DRM core
+        * has already done so for the purpose of setting plane->fb.
+        */
+       plane->fb = fb;
+       plane->crtc = crtc;
+
+       /* src values are in Q16 fixed point, convert to integer: */
        return omap_plane_mode_set(plane, crtc, fb,
                        crtc_x, crtc_y, crtc_w, crtc_h,
-                       src_x, src_y, src_w, src_h,
+                       src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
                        NULL, NULL);
 }
 
 static int omap_plane_disable(struct drm_plane *plane)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
+
        omap_plane->win.rotation = BIT(DRM_ROTATE_0);
-       return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+       omap_plane->info.zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
+                               ? 0 : omap_plane->id;
+
+       return omap_plane_set_enable(plane, false);
 }
 
 static void omap_plane_destroy(struct drm_plane *plane)
@@ -275,7 +273,6 @@ static void omap_plane_destroy(struct drm_plane *plane)
 
        omap_irq_unregister(plane->dev, &omap_plane->error_irq);
 
-       omap_plane_disable(plane);
        drm_plane_cleanup(plane);
 
        drm_flip_work_cleanup(&omap_plane->unpin_work);
@@ -283,18 +280,15 @@ static void omap_plane_destroy(struct drm_plane *plane)
        kfree(omap_plane);
 }
 
-int omap_plane_dpms(struct drm_plane *plane, int mode)
+int omap_plane_set_enable(struct drm_plane *plane, bool enable)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
-       bool enabled = (mode == DRM_MODE_DPMS_ON);
-       int ret = 0;
 
-       if (enabled != omap_plane->enabled) {
-               omap_plane->enabled = enabled;
-               ret = apply(plane);
-       }
+       if (enable == omap_plane->enabled)
+               return 0;
 
-       return ret;
+       omap_plane->enabled = enable;
+       return omap_plane_apply(plane);
 }
 
 /* helper to install properties which are common to planes and crtcs */
@@ -342,61 +336,63 @@ int omap_plane_set_property(struct drm_plane *plane,
        if (property == priv->rotation_prop) {
                DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
                omap_plane->win.rotation = val;
-               ret = apply(plane);
+               ret = omap_plane_apply(plane);
        } else if (property == priv->zorder_prop) {
                DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
                omap_plane->info.zorder = val;
-               ret = apply(plane);
+               ret = omap_plane_apply(plane);
        }
 
        return ret;
 }
 
 static const struct drm_plane_funcs omap_plane_funcs = {
-               .update_plane = omap_plane_update,
-               .disable_plane = omap_plane_disable,
-               .destroy = omap_plane_destroy,
-               .set_property = omap_plane_set_property,
+       .update_plane = omap_plane_update,
+       .disable_plane = omap_plane_disable,
+       .destroy = omap_plane_destroy,
+       .set_property = omap_plane_set_property,
 };
 
 static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
 {
        struct omap_plane *omap_plane =
                        container_of(irq, struct omap_plane, error_irq);
-       DRM_ERROR("%s: errors: %08x\n", omap_plane->name, irqstatus);
+       DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name,
+               irqstatus);
 }
 
 static const char *plane_names[] = {
-               [OMAP_DSS_GFX] = "gfx",
-               [OMAP_DSS_VIDEO1] = "vid1",
-               [OMAP_DSS_VIDEO2] = "vid2",
-               [OMAP_DSS_VIDEO3] = "vid3",
+       [OMAP_DSS_GFX] = "gfx",
+       [OMAP_DSS_VIDEO1] = "vid1",
+       [OMAP_DSS_VIDEO2] = "vid2",
+       [OMAP_DSS_VIDEO3] = "vid3",
 };
 
 static const uint32_t error_irqs[] = {
-               [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
-               [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
-               [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
-               [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
+       [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
+       [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
+       [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
+       [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
 };
 
 /* initialize plane */
 struct drm_plane *omap_plane_init(struct drm_device *dev,
-               int id, bool private_plane)
+               int id, enum drm_plane_type type)
 {
        struct omap_drm_private *priv = dev->dev_private;
-       struct drm_plane *plane = NULL;
+       struct drm_plane *plane;
        struct omap_plane *omap_plane;
        struct omap_overlay_info *info;
+       int ret;
 
-       DBG("%s: priv=%d", plane_names[id], private_plane);
+       DBG("%s: type=%d", plane_names[id], type);
 
        omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
        if (!omap_plane)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        drm_flip_work_init(&omap_plane->unpin_work,
-                       "unpin", unpin_worker);
+                       "unpin", omap_plane_unpin_worker);
 
        omap_plane->nformats = omap_framebuffer_get_formats(
                        omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
@@ -413,8 +409,11 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
        omap_plane->error_irq.irq = omap_plane_error_irq;
        omap_irq_register(dev, &omap_plane->error_irq);
 
-       drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs,
-                       omap_plane->formats, omap_plane->nformats, private_plane);
+       ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1,
+                                      &omap_plane_funcs, omap_plane->formats,
+                                      omap_plane->nformats, type);
+       if (ret < 0)
+               goto error;
 
        omap_plane_install_properties(plane, &plane->base);
 
@@ -432,10 +431,15 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
         * TODO add ioctl to give userspace an API to change this.. this
         * will come in a subsequent patch.
         */
-       if (private_plane)
+       if (type == DRM_PLANE_TYPE_PRIMARY)
                omap_plane->info.zorder = 0;
        else
                omap_plane->info.zorder = id;
 
        return plane;
+
+error:
+       omap_irq_unregister(plane->dev, &omap_plane->error_irq);
+       kfree(omap_plane);
+       return NULL;
 }
index d845837..6d64c7b 100644 (file)
@@ -11,6 +11,7 @@ config DRM_PANEL_SIMPLE
        tristate "support for simple panels"
        depends on OF
        depends on BACKLIGHT_CLASS_DEVICE
+       select VIDEOMODE_HELPERS
        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
index 39806c3..30904a9 100644 (file)
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
 
+#include <video/display_timing.h>
+#include <video/videomode.h>
+
 struct panel_desc {
        const struct drm_display_mode *modes;
        unsigned int num_modes;
+       const struct display_timing *timings;
+       unsigned int num_timings;
 
        unsigned int bpc;
 
@@ -94,6 +99,25 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel)
        if (!panel->desc)
                return 0;
 
+       for (i = 0; i < panel->desc->num_timings; i++) {
+               const struct display_timing *dt = &panel->desc->timings[i];
+               struct videomode vm;
+
+               videomode_from_timing(dt, &vm);
+               mode = drm_mode_create(drm);
+               if (!mode) {
+                       dev_err(drm->dev, "failed to add mode %ux%u\n",
+                               dt->hactive.typ, dt->vactive.typ);
+                       continue;
+               }
+
+               drm_display_mode_from_videomode(&vm, mode);
+               drm_mode_set_name(mode);
+
+               drm_mode_probed_add(connector, mode);
+               num++;
+       }
+
        for (i = 0; i < panel->desc->num_modes; i++) {
                const struct drm_display_mode *m = &panel->desc->modes[i];
 
@@ -226,12 +250,30 @@ static int panel_simple_get_modes(struct drm_panel *panel)
        return num;
 }
 
+static int panel_simple_get_timings(struct drm_panel *panel,
+                                   unsigned int num_timings,
+                                   struct display_timing *timings)
+{
+       struct panel_simple *p = to_panel_simple(panel);
+       unsigned int i;
+
+       if (p->desc->num_timings < num_timings)
+               num_timings = p->desc->num_timings;
+
+       if (timings)
+               for (i = 0; i < num_timings; i++)
+                       timings[i] = p->desc->timings[i];
+
+       return p->desc->num_timings;
+}
+
 static const struct drm_panel_funcs panel_simple_funcs = {
        .disable = panel_simple_disable,
        .unprepare = panel_simple_unprepare,
        .prepare = panel_simple_prepare,
        .enable = panel_simple_enable,
        .get_modes = panel_simple_get_modes,
+       .get_timings = panel_simple_get_timings,
 };
 
 static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
@@ -327,6 +369,31 @@ static void panel_simple_shutdown(struct device *dev)
        panel_simple_disable(&panel->base);
 }
 
+static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = {
+       .clock = 33333,
+       .hdisplay = 800,
+       .hsync_start = 800 + 0,
+       .hsync_end = 800 + 0 + 255,
+       .htotal = 800 + 0 + 255 + 0,
+       .vdisplay = 480,
+       .vsync_start = 480 + 2,
+       .vsync_end = 480 + 2 + 45,
+       .vtotal = 480 + 2 + 45 + 0,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+};
+
+static const struct panel_desc ampire_am800480r3tmqwa1h = {
+       .modes = &ampire_am800480r3tmqwa1h_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 152,
+               .height = 91,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
 static const struct drm_display_mode auo_b101aw03_mode = {
        .clock = 51450,
        .hdisplay = 1024,
@@ -350,6 +417,29 @@ static const struct panel_desc auo_b101aw03 = {
        },
 };
 
+static const struct drm_display_mode auo_b101ean01_mode = {
+       .clock = 72500,
+       .hdisplay = 1280,
+       .hsync_start = 1280 + 119,
+       .hsync_end = 1280 + 119 + 32,
+       .htotal = 1280 + 119 + 32 + 21,
+       .vdisplay = 800,
+       .vsync_start = 800 + 4,
+       .vsync_end = 800 + 4 + 20,
+       .vtotal = 800 + 4 + 20 + 8,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc auo_b101ean01 = {
+       .modes = &auo_b101ean01_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 217,
+               .height = 136,
+       },
+};
+
 static const struct drm_display_mode auo_b101xtn01_mode = {
        .clock = 72000,
        .hdisplay = 1366,
@@ -615,24 +705,25 @@ static const struct panel_desc giantplus_gpg482739qs5 = {
                .width = 95,
                .height = 54,
        },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 };
 
-static const struct drm_display_mode hannstar_hsd070pww1_mode = {
-       .clock = 71100,
-       .hdisplay = 1280,
-       .hsync_start = 1280 + 1,
-       .hsync_end = 1280 + 1 + 158,
-       .htotal = 1280 + 1 + 158 + 1,
-       .vdisplay = 800,
-       .vsync_start = 800 + 1,
-       .vsync_end = 800 + 1 + 21,
-       .vtotal = 800 + 1 + 21 + 1,
-       .vrefresh = 60,
+static const struct display_timing hannstar_hsd070pww1_timing = {
+       .pixelclock = { 64300000, 71100000, 82000000 },
+       .hactive = { 1280, 1280, 1280 },
+       .hfront_porch = { 1, 1, 10 },
+       .hback_porch = { 1, 1, 10 },
+       .hsync_len = { 52, 158, 661 },
+       .vactive = { 800, 800, 800 },
+       .vfront_porch = { 1, 1, 10 },
+       .vback_porch = { 1, 1, 10 },
+       .vsync_len = { 1, 21, 203 },
+       .flags = DISPLAY_FLAGS_DE_HIGH,
 };
 
 static const struct panel_desc hannstar_hsd070pww1 = {
-       .modes = &hannstar_hsd070pww1_mode,
-       .num_modes = 1,
+       .timings = &hannstar_hsd070pww1_timing,
+       .num_timings = 1,
        .bpc = 6,
        .size = {
                .width = 151,
@@ -663,6 +754,31 @@ static const struct panel_desc hitachi_tx23d38vm0caa = {
        },
 };
 
+static const struct drm_display_mode innolux_at043tn24_mode = {
+       .clock = 9000,
+       .hdisplay = 480,
+       .hsync_start = 480 + 2,
+       .hsync_end = 480 + 2 + 41,
+       .htotal = 480 + 2 + 41 + 2,
+       .vdisplay = 272,
+       .vsync_start = 272 + 2,
+       .vsync_end = 272 + 2 + 11,
+       .vtotal = 272 + 2 + 11 + 2,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct panel_desc innolux_at043tn24 = {
+       .modes = &innolux_at043tn24_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 95,
+               .height = 54,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
 static const struct drm_display_mode innolux_g121i1_l01_mode = {
        .clock = 71000,
        .hdisplay = 1280,
@@ -733,6 +849,29 @@ static const struct panel_desc innolux_n156bge_l21 = {
        },
 };
 
+static const struct drm_display_mode innolux_zj070na_01p_mode = {
+       .clock = 51501,
+       .hdisplay = 1024,
+       .hsync_start = 1024 + 128,
+       .hsync_end = 1024 + 128 + 64,
+       .htotal = 1024 + 128 + 64 + 128,
+       .vdisplay = 600,
+       .vsync_start = 600 + 16,
+       .vsync_end = 600 + 16 + 4,
+       .vtotal = 600 + 16 + 4 + 16,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc innolux_zj070na_01p = {
+       .modes = &innolux_zj070na_01p_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 1024,
+               .height = 600,
+       },
+};
+
 static const struct drm_display_mode lg_lp129qe_mode = {
        .clock = 285250,
        .hdisplay = 2560,
@@ -756,6 +895,30 @@ static const struct panel_desc lg_lp129qe = {
        },
 };
 
+static const struct drm_display_mode ortustech_com43h4m85ulc_mode  = {
+       .clock = 25000,
+       .hdisplay = 480,
+       .hsync_start = 480 + 10,
+       .hsync_end = 480 + 10 + 10,
+       .htotal = 480 + 10 + 10 + 15,
+       .vdisplay = 800,
+       .vsync_start = 800 + 3,
+       .vsync_end = 800 + 3 + 3,
+       .vtotal = 800 + 3 + 3 + 3,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc ortustech_com43h4m85ulc = {
+       .modes = &ortustech_com43h4m85ulc_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 56,
+               .height = 93,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
 static const struct drm_display_mode samsung_ltn101nt05_mode = {
        .clock = 54030,
        .hdisplay = 1024,
@@ -779,11 +942,63 @@ static const struct panel_desc samsung_ltn101nt05 = {
        },
 };
 
+static const struct drm_display_mode samsung_ltn140at29_301_mode = {
+       .clock = 76300,
+       .hdisplay = 1366,
+       .hsync_start = 1366 + 64,
+       .hsync_end = 1366 + 64 + 48,
+       .htotal = 1366 + 64 + 48 + 128,
+       .vdisplay = 768,
+       .vsync_start = 768 + 2,
+       .vsync_end = 768 + 2 + 5,
+       .vtotal = 768 + 2 + 5 + 17,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc samsung_ltn140at29_301 = {
+       .modes = &samsung_ltn140at29_301_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 320,
+               .height = 187,
+       },
+};
+
+static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = {
+       .clock = 33300,
+       .hdisplay = 800,
+       .hsync_start = 800 + 1,
+       .hsync_end = 800 + 1 + 64,
+       .htotal = 800 + 1 + 64 + 64,
+       .vdisplay = 480,
+       .vsync_start = 480 + 1,
+       .vsync_end = 480 + 1 + 23,
+       .vtotal = 480 + 1 + 23 + 22,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc shelly_sca07010_bfn_lnn = {
+       .modes = &shelly_sca07010_bfn_lnn_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 152,
+               .height = 91,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
 static const struct of_device_id platform_of_match[] = {
        {
+               .compatible = "ampire,am800480r3tmqwa1h",
+               .data = &ampire_am800480r3tmqwa1h,
+       }, {
                .compatible = "auo,b101aw03",
                .data = &auo_b101aw03,
        }, {
+               .compatible = "auo,b101ean01",
+               .data = &auo_b101ean01,
+       }, {
                .compatible = "auo,b101xtn01",
                .data = &auo_b101xtn01,
        }, {
@@ -826,6 +1041,9 @@ static const struct of_device_id platform_of_match[] = {
                .compatible = "hit,tx23d38vm0caa",
                .data = &hitachi_tx23d38vm0caa
        }, {
+               .compatible = "innolux,at043tn24",
+               .data = &innolux_at043tn24,
+       }, {
                .compatible ="innolux,g121i1-l01",
                .data = &innolux_g121i1_l01
        }, {
@@ -835,12 +1053,24 @@ static const struct of_device_id platform_of_match[] = {
                .compatible = "innolux,n156bge-l21",
                .data = &innolux_n156bge_l21,
        }, {
+               .compatible = "innolux,zj070na-01p",
+               .data = &innolux_zj070na_01p,
+       }, {
                .compatible = "lg,lp129qe",
                .data = &lg_lp129qe,
        }, {
+               .compatible = "ortustech,com43h4m85ulc",
+               .data = &ortustech_com43h4m85ulc,
+       }, {
                .compatible = "samsung,ltn101nt05",
                .data = &samsung_ltn101nt05,
        }, {
+               .compatible = "samsung,ltn140at29-301",
+               .data = &samsung_ltn140at29_301,
+       }, {
+               .compatible = "shelly,sca07010-bfn-lnn",
+               .data = &shelly_sca07010_bfn_lnn,
+       }, {
                /* sentinel */
        }
 };
index 4870df8..0089d83 100644 (file)
 #define VCE_UENC_REG_CLOCK_GATING      0x207c0
 #define VCE_SYS_INT_EN                 0x21300
 #      define VCE_SYS_INT_TRAP_INTERRUPT_EN    (1 << 3)
+#define VCE_LMI_VCPU_CACHE_40BIT_BAR   0x2145c
 #define VCE_LMI_CTRL2                  0x21474
 #define VCE_LMI_CTRL                   0x21498
 #define VCE_LMI_VM_CTRL                        0x214a0
index 35ab65d..73a6432 100644 (file)
@@ -1567,6 +1567,7 @@ struct radeon_dpm {
        int                     new_active_crtc_count;
        u32                     current_active_crtcs;
        int                     current_active_crtc_count;
+       bool single_display;
        struct radeon_dpm_dynamic_state dyn_state;
        struct radeon_dpm_fan fan;
        u32 tdp_limit;
index 63ccb8f..d27e4cc 100644 (file)
@@ -76,7 +76,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
 
 static bool radeon_read_bios(struct radeon_device *rdev)
 {
-       uint8_t __iomem *bios;
+       uint8_t __iomem *bios, val1, val2;
        size_t size;
 
        rdev->bios = NULL;
@@ -86,15 +86,19 @@ static bool radeon_read_bios(struct radeon_device *rdev)
                return false;
        }
 
-       if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+       val1 = readb(&bios[0]);
+       val2 = readb(&bios[1]);
+
+       if (size == 0 || val1 != 0x55 || val2 != 0xaa) {
                pci_unmap_rom(rdev->pdev, bios);
                return false;
        }
-       rdev->bios = kmemdup(bios, size, GFP_KERNEL);
+       rdev->bios = kzalloc(size, GFP_KERNEL);
        if (rdev->bios == NULL) {
                pci_unmap_rom(rdev->pdev, bios);
                return false;
        }
+       memcpy_fromio(rdev->bios, bios, size);
        pci_unmap_rom(rdev->pdev, bios);
        return true;
 }
index 4cdcaf8..3db2300 100644 (file)
@@ -153,7 +153,7 @@ void radeon_kfd_device_init(struct radeon_device *rdev)
                        .compute_vmid_bitmap = 0xFF00,
 
                        .first_compute_pipe = 1,
-                       .compute_pipe_count = 8 - 1,
+                       .compute_pipe_count = 4 - 1,
                };
 
                radeon_doorbell_get_kfd_info(rdev,
index a69bd44..572b4db 100644 (file)
@@ -122,7 +122,6 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
        it = interval_tree_iter_first(&rmn->objects, start, end);
        while (it) {
                struct radeon_bo *bo;
-               struct fence *fence;
                int r;
 
                bo = container_of(it, struct radeon_bo, mn_it);
@@ -134,12 +133,10 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
                        continue;
                }
 
-               fence = reservation_object_get_excl(bo->tbo.resv);
-               if (fence) {
-                       r = radeon_fence_wait((struct radeon_fence *)fence, false);
-                       if (r)
-                               DRM_ERROR("(%d) failed to wait for user bo\n", r);
-               }
+               r = reservation_object_wait_timeout_rcu(bo->tbo.resv, true,
+                       false, MAX_SCHEDULE_TIMEOUT);
+               if (r)
+                       DRM_ERROR("(%d) failed to wait for user bo\n", r);
 
                radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU);
                r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
index 43e0994..318165d 100644 (file)
@@ -173,17 +173,6 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
                else
                        rbo->placements[i].lpfn = 0;
        }
-
-       /*
-        * Use two-ended allocation depending on the buffer size to
-        * improve fragmentation quality.
-        * 512kb was measured as the most optimal number.
-        */
-       if (rbo->tbo.mem.size > 512 * 1024) {
-               for (i = 0; i < c; i++) {
-                       rbo->placements[i].flags |= TTM_PL_FLAG_TOPDOWN;
-               }
-       }
 }
 
 int radeon_bo_create(struct radeon_device *rdev,
index 33cf410..c1ba83a 100644 (file)
@@ -837,12 +837,8 @@ static void radeon_dpm_thermal_work_handler(struct work_struct *work)
        radeon_pm_compute_clocks(rdev);
 }
 
-static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
-                                                    enum radeon_pm_state_type dpm_state)
+static bool radeon_dpm_single_display(struct radeon_device *rdev)
 {
-       int i;
-       struct radeon_ps *ps;
-       u32 ui_class;
        bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ?
                true : false;
 
@@ -858,6 +854,17 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
        if (single_display && (r600_dpm_get_vrefresh(rdev) >= 120))
                single_display = false;
 
+       return single_display;
+}
+
+static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
+                                                    enum radeon_pm_state_type dpm_state)
+{
+       int i;
+       struct radeon_ps *ps;
+       u32 ui_class;
+       bool single_display = radeon_dpm_single_display(rdev);
+
        /* certain older asics have a separare 3D performance state,
         * so try that first if the user selected performance
         */
@@ -983,6 +990,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
        struct radeon_ps *ps;
        enum radeon_pm_state_type dpm_state;
        int ret;
+       bool single_display = radeon_dpm_single_display(rdev);
 
        /* if dpm init failed */
        if (!rdev->pm.dpm_enabled)
@@ -1007,6 +1015,9 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
                /* vce just modifies an existing state so force a change */
                if (ps->vce_active != rdev->pm.dpm.vce_active)
                        goto force;
+               /* user has made a display change (such as timing) */
+               if (rdev->pm.dpm.single_display != single_display)
+                       goto force;
                if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) {
                        /* for pre-BTC and APUs if the num crtcs changed but state is the same,
                         * all we need to do is update the display configuration.
@@ -1069,6 +1080,7 @@ force:
 
        rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
        rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+       rdev->pm.dpm.single_display = single_display;
 
        /* wait for the rings to drain */
        for (i = 0; i < RADEON_NUM_RINGS; i++) {
index 2456f69..8c78723 100644 (file)
@@ -495,7 +495,7 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
        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)
+       if (!ring->ring)
                return 0;
 
        /* print 8 dw before current rptr as often it's the last executed
index d02aa1d..b292aca 100644 (file)
@@ -598,6 +598,10 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
        enum dma_data_direction direction = write ?
                DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
 
+       /* double check that we don't free the table twice */
+       if (!ttm->sg->sgl)
+               return;
+
        /* free the sg table and pages again */
        dma_unmap_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
 
index 1ac7bb8..fbbe78f 100644 (file)
@@ -156,6 +156,9 @@ int vce_v2_0_resume(struct radeon_device *rdev)
        WREG32(VCE_LMI_SWAP_CNTL1, 0);
        WREG32(VCE_LMI_VM_CTRL, 0);
 
+       WREG32(VCE_LMI_VCPU_CACHE_40BIT_BAR, addr >> 8);
+
+       addr &= 0xff;
        size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size);
        WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff);
        WREG32(VCE_VCPU_CACHE_SIZE0, size);
index fb052bc..93117f1 100644 (file)
@@ -509,7 +509,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
        enum rcar_du_encoder_type enc_type = RCAR_DU_ENCODER_NONE;
        struct device_node *connector = NULL;
        struct device_node *encoder = NULL;
-       struct device_node *prev = NULL;
+       struct device_node *ep_node = NULL;
        struct device_node *entity_ep_node;
        struct device_node *entity;
        int ret;
@@ -527,16 +527,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
 
        entity_ep_node = of_parse_phandle(ep->local_node, "remote-endpoint", 0);
 
-       while (1) {
-               struct device_node *ep_node;
-
-               ep_node = of_graph_get_next_endpoint(entity, prev);
-               of_node_put(prev);
-               prev = ep_node;
-
-               if (!ep_node)
-                       break;
-
+       for_each_endpoint_of_node(entity, ep_node) {
                if (ep_node == entity_ep_node)
                        continue;
 
@@ -603,27 +594,19 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
 static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
 {
        struct device_node *np = rcdu->dev->of_node;
-       struct device_node *prev = NULL;
+       struct device_node *ep_node;
        unsigned int num_encoders = 0;
 
        /*
         * Iterate over the endpoints and create one encoder for each output
         * pipeline.
         */
-       while (1) {
-               struct device_node *ep_node;
+       for_each_endpoint_of_node(np, ep_node) {
                enum rcar_du_output output;
                struct of_endpoint ep;
                unsigned int i;
                int ret;
 
-               ep_node = of_graph_get_next_endpoint(np, prev);
-               of_node_put(prev);
-               prev = ep_node;
-
-               if (ep_node == NULL)
-                       break;
-
                ret = of_graph_parse_endpoint(ep_node, &ep);
                if (ret < 0) {
                        of_node_put(ep_node);
index 21a481b..3962176 100644 (file)
@@ -129,6 +129,7 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
        struct rockchip_drm_private *private;
        struct dma_iommu_mapping *mapping;
        struct device *dev = drm_dev->dev;
+       struct drm_connector *connector;
        int ret;
 
        private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL);
@@ -171,6 +172,23 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
        if (ret)
                goto err_detach_device;
 
+       /*
+        * All components are now added, we can publish the connector sysfs
+        * entries to userspace.  This will generate hotplug events and so
+        * userspace will expect to be able to access DRM at this point.
+        */
+       list_for_each_entry(connector, &drm_dev->mode_config.connector_list,
+                       head) {
+               ret = drm_connector_register(connector);
+               if (ret) {
+                       dev_err(drm_dev->dev,
+                               "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n",
+                               connector->base.id,
+                               connector->name, ret);
+                       goto err_unbind;
+               }
+       }
+
        /* init kms poll for handling hpd */
        drm_kms_helper_poll_init(drm_dev);
 
@@ -200,6 +218,7 @@ err_vblank_cleanup:
        drm_vblank_cleanup(drm_dev);
 err_kms_helper_poll_fini:
        drm_kms_helper_poll_fini(drm_dev);
+err_unbind:
        component_unbind_all(dev, drm_dev);
 err_detach_device:
        arm_iommu_detach_device(dev);
@@ -366,7 +385,7 @@ static const struct dev_pm_ops rockchip_drm_pm_ops = {
 int rockchip_drm_encoder_get_mux_id(struct device_node *node,
                                    struct drm_encoder *encoder)
 {
-       struct device_node *ep = NULL;
+       struct device_node *ep;
        struct drm_crtc *crtc = encoder->crtc;
        struct of_endpoint endpoint;
        struct device_node *port;
@@ -375,18 +394,15 @@ int rockchip_drm_encoder_get_mux_id(struct device_node *node,
        if (!node || !crtc)
                return -EINVAL;
 
-       do {
-               ep = of_graph_get_next_endpoint(node, ep);
-               if (!ep)
-                       break;
-
+       for_each_endpoint_of_node(node, ep) {
                port = of_graph_get_remote_port(ep);
                of_node_put(port);
                if (port == crtc->port) {
                        ret = of_graph_parse_endpoint(ep, &endpoint);
+                       of_node_put(ep);
                        return ret ?: endpoint.id;
                }
-       } while (ep);
+       }
 
        return -EINVAL;
 }
index d5c1248..5b0dc0f 100644 (file)
@@ -119,6 +119,9 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
        DRM_DEBUG_KMS("FB [%dx%d]-%d kvaddr=%p offset=%ld size=%d\n",
                      fb->width, fb->height, fb->depth, rk_obj->kvaddr,
                      offset, size);
+
+       fbi->skip_vt_switch = true;
+
        return 0;
 
 err_drm_framebuffer_unref:
index d041921..ccb0ce0 100644 (file)
@@ -421,6 +421,12 @@ static void vop_enable(struct drm_crtc *crtc)
        if (vop->is_enabled)
                return;
 
+       ret = pm_runtime_get_sync(vop->dev);
+       if (ret < 0) {
+               dev_err(vop->dev, "failed to get pm runtime: %d\n", ret);
+               return;
+       }
+
        ret = clk_enable(vop->hclk);
        if (ret < 0) {
                dev_err(vop->dev, "failed to enable hclk - %d\n", ret);
@@ -517,6 +523,7 @@ static void vop_disable(struct drm_crtc *crtc)
        clk_disable(vop->dclk);
        clk_disable(vop->aclk);
        clk_disable(vop->hclk);
+       pm_runtime_put(vop->dev);
 }
 
 /*
@@ -893,7 +900,7 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
        u16 vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
        u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start;
        u16 vact_end = vact_st + vdisplay;
-       int ret;
+       int ret, ret_clk;
        uint32_t val;
 
        /*
@@ -915,7 +922,8 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
        default:
                DRM_ERROR("unsupport connector_type[%d]\n",
                          vop->connector_type);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        };
        VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode);
 
@@ -938,7 +946,7 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
 
        ret = vop_crtc_mode_set_base(crtc, x, y, fb);
        if (ret)
-               return ret;
+               goto out;
 
        /*
         * reset dclk, take all mode config affect, so the clk would run in
@@ -949,13 +957,14 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
        reset_control_deassert(vop->dclk_rst);
 
        clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
-       ret = clk_enable(vop->dclk);
-       if (ret < 0) {
-               dev_err(vop->dev, "failed to enable dclk - %d\n", ret);
-               return ret;
+out:
+       ret_clk = clk_enable(vop->dclk);
+       if (ret_clk < 0) {
+               dev_err(vop->dev, "failed to enable dclk - %d\n", ret_clk);
+               return ret_clk;
        }
 
-       return 0;
+       return ret;
 }
 
 static void vop_crtc_commit(struct drm_crtc *crtc)
index b7f7815..a287e4f 100644 (file)
@@ -425,8 +425,8 @@ static void tegra_plane_reset(struct drm_plane *plane)
 {
        struct tegra_plane_state *state;
 
-       if (plane->state && plane->state->fb)
-               drm_framebuffer_unreference(plane->state->fb);
+       if (plane->state)
+               __drm_atomic_helper_plane_destroy_state(plane, plane->state);
 
        kfree(plane->state);
        plane->state = NULL;
@@ -443,12 +443,14 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla
        struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
        struct tegra_plane_state *copy;
 
-       copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+       copy = kmalloc(sizeof(*copy), GFP_KERNEL);
        if (!copy)
                return NULL;
 
-       if (copy->base.fb)
-               drm_framebuffer_reference(copy->base.fb);
+       __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
+       copy->tiling = state->tiling;
+       copy->format = state->format;
+       copy->swap = state->swap;
 
        return &copy->base;
 }
@@ -456,9 +458,7 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla
 static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
                                             struct drm_plane_state *state)
 {
-       if (state->fb)
-               drm_framebuffer_unreference(state->fb);
-
+       __drm_atomic_helper_plane_destroy_state(plane, state);
        kfree(state);
 }
 
@@ -908,6 +908,15 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
        return 0;
 }
 
+u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc)
+{
+       if (dc->syncpt)
+               return host1x_syncpt_read(dc->syncpt);
+
+       /* fallback to software emulated VBLANK counter */
+       return drm_crtc_vblank_count(&dc->base);
+}
+
 void tegra_dc_enable_vblank(struct tegra_dc *dc)
 {
        unsigned long value, flags;
@@ -995,6 +1004,9 @@ static void tegra_crtc_reset(struct drm_crtc *crtc)
 {
        struct tegra_dc_state *state;
 
+       if (crtc->state)
+               __drm_atomic_helper_crtc_destroy_state(crtc, crtc->state);
+
        kfree(crtc->state);
        crtc->state = NULL;
 
@@ -1011,14 +1023,15 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
        struct tegra_dc_state *state = to_dc_state(crtc->state);
        struct tegra_dc_state *copy;
 
-       copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+       copy = kmalloc(sizeof(*copy), GFP_KERNEL);
        if (!copy)
                return NULL;
 
-       copy->base.mode_changed = false;
-       copy->base.active_changed = false;
-       copy->base.planes_changed = false;
-       copy->base.event = NULL;
+       __drm_atomic_helper_crtc_duplicate_state(crtc, &copy->base);
+       copy->clk = state->clk;
+       copy->pclk = state->pclk;
+       copy->div = state->div;
+       copy->planes = state->planes;
 
        return &copy->base;
 }
@@ -1026,6 +1039,7 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
                                            struct drm_crtc_state *state)
 {
+       __drm_atomic_helper_crtc_destroy_state(crtc, state);
        kfree(state);
 }
 
@@ -1152,26 +1166,18 @@ static int tegra_dc_set_timings(struct tegra_dc *dc,
        return 0;
 }
 
-int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
-                        unsigned long pclk, unsigned int div)
-{
-       u32 value;
-       int err;
-
-       err = clk_set_parent(dc->clk, parent);
-       if (err < 0) {
-               dev_err(dc->dev, "failed to set parent clock: %d\n", err);
-               return err;
-       }
-
-       DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), div);
-
-       value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1;
-       tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
-
-       return 0;
-}
-
+/**
+ * tegra_dc_state_setup_clock - check clock settings and store them in atomic
+ *     state
+ * @dc: display controller
+ * @crtc_state: CRTC atomic state
+ * @clk: parent clock for display controller
+ * @pclk: pixel clock
+ * @div: shift clock divider
+ *
+ * Returns:
+ * 0 on success or a negative error-code on failure.
+ */
 int tegra_dc_state_setup_clock(struct tegra_dc *dc,
                               struct drm_crtc_state *crtc_state,
                               struct clk *clk, unsigned long pclk,
@@ -1179,6 +1185,9 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc,
 {
        struct tegra_dc_state *state = to_dc_state(crtc_state);
 
+       if (!clk_has_parent(dc->clk, clk))
+               return -EINVAL;
+
        state->clk = clk;
        state->pclk = pclk;
        state->div = div;
@@ -1294,9 +1303,7 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc)
 static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
        .disable = tegra_crtc_disable,
        .mode_fixup = tegra_crtc_mode_fixup,
-       .mode_set = drm_helper_crtc_mode_set,
        .mode_set_nofb = tegra_crtc_mode_set_nofb,
-       .mode_set_base = drm_helper_crtc_mode_set_base,
        .prepare = tegra_crtc_prepare,
        .commit = tegra_crtc_commit,
        .atomic_check = tegra_crtc_atomic_check,
@@ -1631,7 +1638,6 @@ static int tegra_dc_init(struct host1x_client *client)
        struct tegra_drm *tegra = drm->dev_private;
        struct drm_plane *primary = NULL;
        struct drm_plane *cursor = NULL;
-       unsigned int syncpt;
        u32 value;
        int err;
 
@@ -1700,13 +1706,15 @@ static int tegra_dc_init(struct host1x_client *client)
        }
 
        /* initialize display controller */
-       if (dc->pipe)
-               syncpt = SYNCPT_VBLANK1;
-       else
-               syncpt = SYNCPT_VBLANK0;
+       if (dc->syncpt) {
+               u32 syncpt = host1x_syncpt_id(dc->syncpt);
 
-       tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
-       tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
+               value = SYNCPT_CNTRL_NO_STALL;
+               tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
+
+               value = SYNCPT_VSYNC_ENABLE | syncpt;
+               tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC);
+       }
 
        value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
        tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
@@ -1874,6 +1882,7 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
 
 static int tegra_dc_probe(struct platform_device *pdev)
 {
+       unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
        const struct of_device_id *id;
        struct resource *regs;
        struct tegra_dc *dc;
@@ -1965,6 +1974,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
                return err;
        }
 
+       dc->syncpt = host1x_syncpt_request(&pdev->dev, flags);
+       if (!dc->syncpt)
+               dev_warn(&pdev->dev, "failed to allocate syncpoint\n");
+
        platform_set_drvdata(pdev, dc);
 
        return 0;
@@ -1975,6 +1988,8 @@ static int tegra_dc_remove(struct platform_device *pdev)
        struct tegra_dc *dc = platform_get_drvdata(pdev);
        int err;
 
+       host1x_syncpt_free(dc->syncpt);
+
        err = host1x_client_unregister(&dc->client);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
index 705c93b..55792da 100644 (file)
@@ -12,6 +12,8 @@
 
 #define DC_CMD_GENERAL_INCR_SYNCPT             0x000
 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL       0x001
+#define  SYNCPT_CNTRL_NO_STALL   (1 << 8)
+#define  SYNCPT_CNTRL_SOFT_RESET (1 << 0)
 #define DC_CMD_GENERAL_INCR_SYNCPT_ERROR       0x002
 #define DC_CMD_WIN_A_INCR_SYNCPT               0x008
 #define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL         0x009
@@ -23,6 +25,7 @@
 #define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL         0x019
 #define DC_CMD_WIN_C_INCR_SYNCPT_ERROR         0x01a
 #define DC_CMD_CONT_SYNCPT_VSYNC               0x028
+#define  SYNCPT_VSYNC_ENABLE (1 << 8)
 #define DC_CMD_DISPLAY_COMMAND_OPTION0         0x031
 #define DC_CMD_DISPLAY_COMMAND                 0x032
 #define DISP_CTRL_MODE_STOP (0 << 5)
 #define DC_WINBUF_BD_UFLOW_STATUS              0xdca
 #define DC_WINBUF_CD_UFLOW_STATUS              0xfca
 
-/* synchronization points */
-#define SYNCPT_VBLANK0 26
-#define SYNCPT_VBLANK1 27
-
 #endif /* TEGRA_DC_H */
index 5f18807..1833abd 100644 (file)
@@ -172,6 +172,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
         */
        drm->irq_enabled = true;
 
+       /* syncpoints are used for full 32-bit hardware VBLANK counters */
+       drm->vblank_disable_immediate = true;
+       drm->max_vblank_count = 0xffffffff;
+
        err = drm_vblank_init(drm, drm->mode_config.num_crtc);
        if (err < 0)
                goto device;
@@ -813,12 +817,12 @@ static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm,
 static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe)
 {
        struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+       struct tegra_dc *dc = to_tegra_dc(crtc);
 
        if (!crtc)
                return 0;
 
-       /* TODO: implement real hardware counter using syncpoints */
-       return drm_crtc_vblank_count(crtc);
+       return tegra_dc_get_vblank_counter(dc);
 }
 
 static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
@@ -879,8 +883,18 @@ static int tegra_debugfs_framebuffers(struct seq_file *s, void *data)
        return 0;
 }
 
+static int tegra_debugfs_iova(struct seq_file *s, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *)s->private;
+       struct drm_device *drm = node->minor->dev;
+       struct tegra_drm *tegra = drm->dev_private;
+
+       return drm_mm_dump_table(s, &tegra->mm);
+}
+
 static struct drm_info_list tegra_debugfs_list[] = {
        { "framebuffers", tegra_debugfs_framebuffers, 0 },
+       { "iova", tegra_debugfs_iova, 0 },
 };
 
 static int tegra_debugfs_init(struct drm_minor *minor)
index 8cb2dfe..659b2fc 100644 (file)
@@ -106,6 +106,7 @@ struct tegra_output;
 
 struct tegra_dc {
        struct host1x_client client;
+       struct host1x_syncpt *syncpt;
        struct device *dev;
        spinlock_t lock;
 
@@ -180,12 +181,11 @@ struct tegra_dc_window {
 };
 
 /* from dc.c */
+u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc);
 void tegra_dc_enable_vblank(struct tegra_dc *dc);
 void tegra_dc_disable_vblank(struct tegra_dc *dc);
 void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
 void tegra_dc_commit(struct tegra_dc *dc);
-int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
-                        unsigned long pclk, unsigned int div);
 int tegra_dc_state_setup_clock(struct tegra_dc *dc,
                               struct drm_crtc_state *crtc_state,
                               struct clk *clk, unsigned long pclk,
index 7eaaee7..06ab178 100644 (file)
@@ -952,7 +952,7 @@ static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        tegra_hdmi_writel(hdmi,
-                         SOR_SEQ_CTL_PU_PC(0) |
+                         SOR_SEQ_PU_PC(0) |
                          SOR_SEQ_PU_PC_ALT(0) |
                          SOR_SEQ_PD_PC(8) |
                          SOR_SEQ_PD_PC_ALT(8),
@@ -1394,8 +1394,8 @@ static int tegra_hdmi_exit(struct host1x_client *client)
 
        tegra_output_exit(&hdmi->output);
 
-       clk_disable_unprepare(hdmi->clk);
        reset_control_assert(hdmi->rst);
+       clk_disable_unprepare(hdmi->clk);
 
        regulator_disable(hdmi->vdd);
        regulator_disable(hdmi->pll);
index 919a19d..a882514 100644 (file)
 #define HDMI_NV_PDISP_SOR_CRCB                                 0x5d
 #define HDMI_NV_PDISP_SOR_BLANK                                        0x5e
 #define HDMI_NV_PDISP_SOR_SEQ_CTL                              0x5f
-#define SOR_SEQ_CTL_PU_PC(x) (((x) & 0xf) <<  0)
+#define SOR_SEQ_PU_PC(x)     (((x) & 0xf) <<  0)
 #define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) <<  4)
 #define SOR_SEQ_PD_PC(x)     (((x) & 0xf) <<  8)
 #define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12)
index 2afe478..7591d89 100644 (file)
@@ -41,6 +41,8 @@ struct tegra_sor {
        struct mutex lock;
        bool enabled;
 
+       struct drm_info_list *debugfs_files;
+       struct drm_minor *minor;
        struct dentry *debugfs;
 };
 
@@ -68,13 +70,12 @@ static inline struct tegra_sor *to_sor(struct tegra_output *output)
        return container_of(output, struct tegra_sor, output);
 }
 
-static inline unsigned long tegra_sor_readl(struct tegra_sor *sor,
-                                           unsigned long offset)
+static inline u32 tegra_sor_readl(struct tegra_sor *sor, unsigned long offset)
 {
        return readl(sor->regs + (offset << 2));
 }
 
-static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value,
+static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value,
                                    unsigned long offset)
 {
        writel(value, sor->regs + (offset << 2));
@@ -83,9 +84,9 @@ static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value,
 static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
                                   struct drm_dp_link *link)
 {
-       unsigned long value;
        unsigned int i;
        u8 pattern;
+       u32 value;
        int err;
 
        /* setup lane parameters */
@@ -202,7 +203,7 @@ static void tegra_sor_update(struct tegra_sor *sor)
 
 static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout)
 {
-       unsigned long value;
+       u32 value;
 
        value = tegra_sor_readl(sor, SOR_PWM_DIV);
        value &= ~SOR_PWM_DIV_MASK;
@@ -281,7 +282,7 @@ static int tegra_sor_wakeup(struct tegra_sor *sor)
 
 static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout)
 {
-       unsigned long value;
+       u32 value;
 
        value = tegra_sor_readl(sor, SOR_PWR);
        value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU;
@@ -674,38 +675,195 @@ static const struct file_operations tegra_sor_crc_fops = {
        .release = tegra_sor_crc_release,
 };
 
+static int tegra_sor_show_regs(struct seq_file *s, void *data)
+{
+       struct drm_info_node *node = s->private;
+       struct tegra_sor *sor = node->info_ent->data;
+
+#define DUMP_REG(name)                                         \
+       seq_printf(s, "%-38s %#05x %08x\n", #name, name,        \
+                  tegra_sor_readl(sor, name))
+
+       DUMP_REG(SOR_CTXSW);
+       DUMP_REG(SOR_SUPER_STATE_0);
+       DUMP_REG(SOR_SUPER_STATE_1);
+       DUMP_REG(SOR_STATE_0);
+       DUMP_REG(SOR_STATE_1);
+       DUMP_REG(SOR_HEAD_STATE_0(0));
+       DUMP_REG(SOR_HEAD_STATE_0(1));
+       DUMP_REG(SOR_HEAD_STATE_1(0));
+       DUMP_REG(SOR_HEAD_STATE_1(1));
+       DUMP_REG(SOR_HEAD_STATE_2(0));
+       DUMP_REG(SOR_HEAD_STATE_2(1));
+       DUMP_REG(SOR_HEAD_STATE_3(0));
+       DUMP_REG(SOR_HEAD_STATE_3(1));
+       DUMP_REG(SOR_HEAD_STATE_4(0));
+       DUMP_REG(SOR_HEAD_STATE_4(1));
+       DUMP_REG(SOR_HEAD_STATE_5(0));
+       DUMP_REG(SOR_HEAD_STATE_5(1));
+       DUMP_REG(SOR_CRC_CNTRL);
+       DUMP_REG(SOR_DP_DEBUG_MVID);
+       DUMP_REG(SOR_CLK_CNTRL);
+       DUMP_REG(SOR_CAP);
+       DUMP_REG(SOR_PWR);
+       DUMP_REG(SOR_TEST);
+       DUMP_REG(SOR_PLL_0);
+       DUMP_REG(SOR_PLL_1);
+       DUMP_REG(SOR_PLL_2);
+       DUMP_REG(SOR_PLL_3);
+       DUMP_REG(SOR_CSTM);
+       DUMP_REG(SOR_LVDS);
+       DUMP_REG(SOR_CRC_A);
+       DUMP_REG(SOR_CRC_B);
+       DUMP_REG(SOR_BLANK);
+       DUMP_REG(SOR_SEQ_CTL);
+       DUMP_REG(SOR_LANE_SEQ_CTL);
+       DUMP_REG(SOR_SEQ_INST(0));
+       DUMP_REG(SOR_SEQ_INST(1));
+       DUMP_REG(SOR_SEQ_INST(2));
+       DUMP_REG(SOR_SEQ_INST(3));
+       DUMP_REG(SOR_SEQ_INST(4));
+       DUMP_REG(SOR_SEQ_INST(5));
+       DUMP_REG(SOR_SEQ_INST(6));
+       DUMP_REG(SOR_SEQ_INST(7));
+       DUMP_REG(SOR_SEQ_INST(8));
+       DUMP_REG(SOR_SEQ_INST(9));
+       DUMP_REG(SOR_SEQ_INST(10));
+       DUMP_REG(SOR_SEQ_INST(11));
+       DUMP_REG(SOR_SEQ_INST(12));
+       DUMP_REG(SOR_SEQ_INST(13));
+       DUMP_REG(SOR_SEQ_INST(14));
+       DUMP_REG(SOR_SEQ_INST(15));
+       DUMP_REG(SOR_PWM_DIV);
+       DUMP_REG(SOR_PWM_CTL);
+       DUMP_REG(SOR_VCRC_A_0);
+       DUMP_REG(SOR_VCRC_A_1);
+       DUMP_REG(SOR_VCRC_B_0);
+       DUMP_REG(SOR_VCRC_B_1);
+       DUMP_REG(SOR_CCRC_A_0);
+       DUMP_REG(SOR_CCRC_A_1);
+       DUMP_REG(SOR_CCRC_B_0);
+       DUMP_REG(SOR_CCRC_B_1);
+       DUMP_REG(SOR_EDATA_A_0);
+       DUMP_REG(SOR_EDATA_A_1);
+       DUMP_REG(SOR_EDATA_B_0);
+       DUMP_REG(SOR_EDATA_B_1);
+       DUMP_REG(SOR_COUNT_A_0);
+       DUMP_REG(SOR_COUNT_A_1);
+       DUMP_REG(SOR_COUNT_B_0);
+       DUMP_REG(SOR_COUNT_B_1);
+       DUMP_REG(SOR_DEBUG_A_0);
+       DUMP_REG(SOR_DEBUG_A_1);
+       DUMP_REG(SOR_DEBUG_B_0);
+       DUMP_REG(SOR_DEBUG_B_1);
+       DUMP_REG(SOR_TRIG);
+       DUMP_REG(SOR_MSCHECK);
+       DUMP_REG(SOR_XBAR_CTRL);
+       DUMP_REG(SOR_XBAR_POL);
+       DUMP_REG(SOR_DP_LINKCTL_0);
+       DUMP_REG(SOR_DP_LINKCTL_1);
+       DUMP_REG(SOR_LANE_DRIVE_CURRENT_0);
+       DUMP_REG(SOR_LANE_DRIVE_CURRENT_1);
+       DUMP_REG(SOR_LANE4_DRIVE_CURRENT_0);
+       DUMP_REG(SOR_LANE4_DRIVE_CURRENT_1);
+       DUMP_REG(SOR_LANE_PREEMPHASIS_0);
+       DUMP_REG(SOR_LANE_PREEMPHASIS_1);
+       DUMP_REG(SOR_LANE4_PREEMPHASIS_0);
+       DUMP_REG(SOR_LANE4_PREEMPHASIS_1);
+       DUMP_REG(SOR_LANE_POST_CURSOR_0);
+       DUMP_REG(SOR_LANE_POST_CURSOR_1);
+       DUMP_REG(SOR_DP_CONFIG_0);
+       DUMP_REG(SOR_DP_CONFIG_1);
+       DUMP_REG(SOR_DP_MN_0);
+       DUMP_REG(SOR_DP_MN_1);
+       DUMP_REG(SOR_DP_PADCTL_0);
+       DUMP_REG(SOR_DP_PADCTL_1);
+       DUMP_REG(SOR_DP_DEBUG_0);
+       DUMP_REG(SOR_DP_DEBUG_1);
+       DUMP_REG(SOR_DP_SPARE_0);
+       DUMP_REG(SOR_DP_SPARE_1);
+       DUMP_REG(SOR_DP_AUDIO_CTRL);
+       DUMP_REG(SOR_DP_AUDIO_HBLANK_SYMBOLS);
+       DUMP_REG(SOR_DP_AUDIO_VBLANK_SYMBOLS);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_HEADER);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_0);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_1);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_2);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_3);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_4);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_5);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_6);
+       DUMP_REG(SOR_DP_TPG);
+       DUMP_REG(SOR_DP_TPG_CONFIG);
+       DUMP_REG(SOR_DP_LQ_CSTM_0);
+       DUMP_REG(SOR_DP_LQ_CSTM_1);
+       DUMP_REG(SOR_DP_LQ_CSTM_2);
+
+#undef DUMP_REG
+
+       return 0;
+}
+
+static const struct drm_info_list debugfs_files[] = {
+       { "regs", tegra_sor_show_regs, 0, NULL },
+};
+
 static int tegra_sor_debugfs_init(struct tegra_sor *sor,
                                  struct drm_minor *minor)
 {
        struct dentry *entry;
+       unsigned int i;
        int err = 0;
 
        sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root);
        if (!sor->debugfs)
                return -ENOMEM;
 
+       sor->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
+                                    GFP_KERNEL);
+       if (!sor->debugfs_files) {
+               err = -ENOMEM;
+               goto remove;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
+               sor->debugfs_files[i].data = sor;
+
+       err = drm_debugfs_create_files(sor->debugfs_files,
+                                      ARRAY_SIZE(debugfs_files),
+                                      sor->debugfs, minor);
+       if (err < 0)
+               goto free;
+
        entry = debugfs_create_file("crc", 0644, sor->debugfs, sor,
                                    &tegra_sor_crc_fops);
        if (!entry) {
-               dev_err(sor->dev,
-                       "cannot create /sys/kernel/debug/dri/%s/sor/crc\n",
-                       minor->debugfs_root->d_name.name);
                err = -ENOMEM;
-               goto remove;
+               goto free;
        }
 
        return err;
 
+free:
+       kfree(sor->debugfs_files);
+       sor->debugfs_files = NULL;
 remove:
-       debugfs_remove(sor->debugfs);
+       debugfs_remove_recursive(sor->debugfs);
        sor->debugfs = NULL;
        return err;
 }
 
 static void tegra_sor_debugfs_exit(struct tegra_sor *sor)
 {
-       debugfs_remove_recursive(sor->debugfs);
+       drm_debugfs_remove_files(sor->debugfs_files, ARRAY_SIZE(debugfs_files),
+                                sor->minor);
+       sor->minor = NULL;
+
+       kfree(sor->debugfs_files);
        sor->debugfs = NULL;
+
+       debugfs_remove_recursive(sor->debugfs);
+       sor->debugfs_files = NULL;
 }
 
 static void tegra_sor_connector_dpms(struct drm_connector *connector, int mode)
@@ -791,8 +949,8 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
        struct tegra_sor_config config;
        struct drm_dp_link link;
        struct drm_dp_aux *aux;
-       unsigned long value;
        int err = 0;
+       u32 value;
 
        mutex_lock(&sor->lock);
 
@@ -1354,12 +1512,30 @@ static int tegra_sor_init(struct host1x_client *client)
                }
        }
 
+       /*
+        * XXX: Remove this reset once proper hand-over from firmware to
+        * kernel is possible.
+        */
+       err = reset_control_assert(sor->rst);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to assert SOR reset: %d\n", err);
+               return err;
+       }
+
        err = clk_prepare_enable(sor->clk);
        if (err < 0) {
                dev_err(sor->dev, "failed to enable clock: %d\n", err);
                return err;
        }
 
+       usleep_range(1000, 3000);
+
+       err = reset_control_deassert(sor->rst);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to deassert SOR reset: %d\n", err);
+               return err;
+       }
+
        err = clk_prepare_enable(sor->clk_safe);
        if (err < 0)
                return err;
diff --git a/drivers/gpu/drm/vgem/Makefile b/drivers/gpu/drm/vgem/Makefile
new file mode 100644 (file)
index 0000000..1055cb7
--- /dev/null
@@ -0,0 +1,4 @@
+ccflags-y := -Iinclude/drm
+vgem-y := vgem_drv.o vgem_dma_buf.o
+
+obj-$(CONFIG_DRM_VGEM) += vgem.o
diff --git a/drivers/gpu/drm/vgem/vgem_dma_buf.c b/drivers/gpu/drm/vgem/vgem_dma_buf.c
new file mode 100644 (file)
index 0000000..0254438
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright Â© 2012 Intel Corporation
+ * Copyright Â© 2014 The Chromium OS Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#include <linux/dma-buf.h>
+#include "vgem_drv.h"
+
+struct sg_table *vgem_gem_prime_get_sg_table(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       BUG_ON(obj->pages == NULL);
+
+       return drm_prime_pages_to_sg(obj->pages, obj->base.size / PAGE_SIZE);
+}
+
+int vgem_gem_prime_pin(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       return vgem_gem_get_pages(obj);
+}
+
+void vgem_gem_prime_unpin(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       vgem_gem_put_pages(obj);
+}
+
+void *vgem_gem_prime_vmap(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       BUG_ON(obj->pages == NULL);
+
+       return vmap(obj->pages, obj->base.size / PAGE_SIZE, 0, PAGE_KERNEL);
+}
+
+void vgem_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+       vunmap(vaddr);
+}
+
+struct drm_gem_object *vgem_gem_prime_import(struct drm_device *dev,
+                                            struct dma_buf *dma_buf)
+{
+       struct drm_vgem_gem_object *obj = NULL;
+       int ret;
+
+       obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+       if (obj == NULL) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = drm_gem_object_init(dev, &obj->base, dma_buf->size);
+       if (ret) {
+               ret = -ENOMEM;
+               goto fail_free;
+       }
+
+       get_dma_buf(dma_buf);
+
+       obj->base.dma_buf = dma_buf;
+       obj->use_dma_buf = true;
+
+       return &obj->base;
+
+fail_free:
+       kfree(obj);
+fail:
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
new file mode 100644 (file)
index 0000000..cb3b435
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ * Copyright Â© 2014 The Chromium OS Authors
+ *
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * them 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 MERCHANTIBILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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:
+ *     Adam Jackson <ajax@redhat.com>
+ *     Ben Widawsky <ben@bwidawsk.net>
+ */
+
+/**
+ * This is vgem, a (non-hardware-backed) GEM service.  This is used by Mesa's
+ * software renderer and the X server for efficient buffer sharing.
+ */
+
+#include <linux/module.h>
+#include <linux/ramfs.h>
+#include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
+#include "vgem_drv.h"
+
+#define DRIVER_NAME    "vgem"
+#define DRIVER_DESC    "Virtual GEM provider"
+#define DRIVER_DATE    "20120112"
+#define DRIVER_MAJOR   1
+#define DRIVER_MINOR   0
+
+void vgem_gem_put_pages(struct drm_vgem_gem_object *obj)
+{
+       drm_gem_put_pages(&obj->base, obj->pages, false, false);
+       obj->pages = NULL;
+}
+
+static void vgem_gem_free_object(struct drm_gem_object *obj)
+{
+       struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj);
+
+       drm_gem_free_mmap_offset(obj);
+
+       if (vgem_obj->use_dma_buf && obj->dma_buf) {
+               dma_buf_put(obj->dma_buf);
+               obj->dma_buf = NULL;
+       }
+
+       drm_gem_object_release(obj);
+
+       if (vgem_obj->pages)
+               vgem_gem_put_pages(vgem_obj);
+
+       vgem_obj->pages = NULL;
+
+       kfree(vgem_obj);
+}
+
+int vgem_gem_get_pages(struct drm_vgem_gem_object *obj)
+{
+       struct page **pages;
+
+       if (obj->pages || obj->use_dma_buf)
+               return 0;
+
+       pages = drm_gem_get_pages(&obj->base);
+       if (IS_ERR(pages)) {
+               return PTR_ERR(pages);
+       }
+
+       obj->pages = pages;
+
+       return 0;
+}
+
+static int vgem_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct drm_vgem_gem_object *obj = vma->vm_private_data;
+       struct drm_device *dev = obj->base.dev;
+       loff_t num_pages;
+       pgoff_t page_offset;
+       int ret;
+
+       /* We don't use vmf->pgoff since that has the fake offset */
+       page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >>
+               PAGE_SHIFT;
+
+       num_pages = DIV_ROUND_UP(obj->base.size, PAGE_SIZE);
+
+       if (page_offset > num_pages)
+               return VM_FAULT_SIGBUS;
+
+       mutex_lock(&dev->struct_mutex);
+
+       ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address,
+                            obj->pages[page_offset]);
+
+       mutex_unlock(&dev->struct_mutex);
+       switch (ret) {
+       case 0:
+               return VM_FAULT_NOPAGE;
+       case -ENOMEM:
+               return VM_FAULT_OOM;
+       case -EBUSY:
+               return VM_FAULT_RETRY;
+       case -EFAULT:
+       case -EINVAL:
+               return VM_FAULT_SIGBUS;
+       default:
+               WARN_ON(1);
+               return VM_FAULT_SIGBUS;
+       }
+}
+
+static struct vm_operations_struct vgem_gem_vm_ops = {
+       .fault = vgem_gem_fault,
+       .open = drm_gem_vm_open,
+       .close = drm_gem_vm_close,
+};
+
+/* ioctls */
+
+static struct drm_gem_object *vgem_gem_create(struct drm_device *dev,
+                                             struct drm_file *file,
+                                             unsigned int *handle,
+                                             unsigned long size)
+{
+       struct drm_vgem_gem_object *obj;
+       struct drm_gem_object *gem_object;
+       int err;
+
+       size = roundup(size, PAGE_SIZE);
+
+       obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+       if (!obj)
+               return ERR_PTR(-ENOMEM);
+
+       gem_object = &obj->base;
+
+       err = drm_gem_object_init(dev, gem_object, size);
+       if (err)
+               goto out;
+
+       err = drm_gem_handle_create(file, gem_object, handle);
+       if (err)
+               goto handle_out;
+
+       drm_gem_object_unreference_unlocked(gem_object);
+
+       return gem_object;
+
+handle_out:
+       drm_gem_object_release(gem_object);
+out:
+       kfree(obj);
+       return ERR_PTR(err);
+}
+
+static int vgem_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
+                               struct drm_mode_create_dumb *args)
+{
+       struct drm_gem_object *gem_object;
+       uint64_t size;
+       uint64_t pitch = args->width * DIV_ROUND_UP(args->bpp, 8);
+
+       size = args->height * pitch;
+       if (size == 0)
+               return -EINVAL;
+
+       gem_object = vgem_gem_create(dev, file, &args->handle, size);
+
+       if (IS_ERR(gem_object)) {
+               DRM_DEBUG_DRIVER("object creation failed\n");
+               return PTR_ERR(gem_object);
+       }
+
+       args->size = gem_object->size;
+       args->pitch = pitch;
+
+       DRM_DEBUG_DRIVER("Created object of size %lld\n", size);
+
+       return 0;
+}
+
+int vgem_gem_dumb_map(struct drm_file *file, struct drm_device *dev,
+                     uint32_t handle, uint64_t *offset)
+{
+       int ret = 0;
+       struct drm_gem_object *obj;
+
+       mutex_lock(&dev->struct_mutex);
+       obj = drm_gem_object_lookup(dev, file, handle);
+       if (!obj) {
+               ret = -ENOENT;
+               goto unlock;
+       }
+
+       if (!drm_vma_node_has_offset(&obj->vma_node)) {
+               ret = drm_gem_create_mmap_offset(obj);
+               if (ret)
+                       goto unref;
+       }
+
+       BUG_ON(!obj->filp);
+
+       obj->filp->private_data = obj;
+
+       ret = vgem_gem_get_pages(to_vgem_bo(obj));
+       if (ret)
+               goto fail_get_pages;
+
+       *offset = drm_vma_node_offset_addr(&obj->vma_node);
+
+       goto unref;
+
+fail_get_pages:
+       drm_gem_free_mmap_offset(obj);
+unref:
+       drm_gem_object_unreference(obj);
+unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+int vgem_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_vma_offset_node *node;
+       struct drm_gem_object *obj;
+       struct drm_vgem_gem_object *vgem_obj;
+       int ret = 0;
+
+       mutex_lock(&dev->struct_mutex);
+
+       node = drm_vma_offset_exact_lookup(dev->vma_offset_manager,
+                                          vma->vm_pgoff,
+                                          vma_pages(vma));
+       if (!node) {
+               ret = -EINVAL;
+               goto out_unlock;
+       } else if (!drm_vma_node_is_allowed(node, filp)) {
+               ret = -EACCES;
+               goto out_unlock;
+       }
+
+       obj = container_of(node, struct drm_gem_object, vma_node);
+
+       vgem_obj = to_vgem_bo(obj);
+
+       if (obj->dma_buf && vgem_obj->use_dma_buf) {
+               ret = dma_buf_mmap(obj->dma_buf, vma, 0);
+               goto out_unlock;
+       }
+
+       if (!obj->dev->driver->gem_vm_ops) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
+       vma->vm_ops = obj->dev->driver->gem_vm_ops;
+       vma->vm_private_data = vgem_obj;
+       vma->vm_page_prot =
+               pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+
+       mutex_unlock(&dev->struct_mutex);
+       drm_gem_vm_open(vma);
+       return ret;
+
+out_unlock:
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
+}
+
+
+static struct drm_ioctl_desc vgem_ioctls[] = {
+};
+
+static const struct file_operations vgem_driver_fops = {
+       .owner          = THIS_MODULE,
+       .open           = drm_open,
+       .mmap           = vgem_drm_gem_mmap,
+       .poll           = drm_poll,
+       .read           = drm_read,
+       .unlocked_ioctl = drm_ioctl,
+       .release        = drm_release,
+};
+
+static struct drm_driver vgem_driver = {
+       .driver_features                = DRIVER_GEM | DRIVER_PRIME,
+       .gem_free_object                = vgem_gem_free_object,
+       .gem_vm_ops                     = &vgem_gem_vm_ops,
+       .ioctls                         = vgem_ioctls,
+       .fops                           = &vgem_driver_fops,
+       .dumb_create                    = vgem_gem_dumb_create,
+       .dumb_map_offset                = vgem_gem_dumb_map,
+       .prime_handle_to_fd             = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle             = drm_gem_prime_fd_to_handle,
+       .gem_prime_export               = drm_gem_prime_export,
+       .gem_prime_import               = vgem_gem_prime_import,
+       .gem_prime_pin                  = vgem_gem_prime_pin,
+       .gem_prime_unpin                = vgem_gem_prime_unpin,
+       .gem_prime_get_sg_table         = vgem_gem_prime_get_sg_table,
+       .gem_prime_vmap                 = vgem_gem_prime_vmap,
+       .gem_prime_vunmap               = vgem_gem_prime_vunmap,
+       .name   = DRIVER_NAME,
+       .desc   = DRIVER_DESC,
+       .date   = DRIVER_DATE,
+       .major  = DRIVER_MAJOR,
+       .minor  = DRIVER_MINOR,
+};
+
+struct drm_device *vgem_device;
+
+static int __init vgem_init(void)
+{
+       int ret;
+
+       vgem_device = drm_dev_alloc(&vgem_driver, NULL);
+       if (!vgem_device) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret  = drm_dev_register(vgem_device, 0);
+
+       if (ret)
+               goto out_unref;
+
+       return 0;
+
+out_unref:
+       drm_dev_unref(vgem_device);
+out:
+       return ret;
+}
+
+static void __exit vgem_exit(void)
+{
+       drm_dev_unregister(vgem_device);
+       drm_dev_unref(vgem_device);
+}
+
+module_init(vgem_init);
+module_exit(vgem_exit);
+
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/vgem/vgem_drv.h b/drivers/gpu/drm/vgem/vgem_drv.h
new file mode 100644 (file)
index 0000000..57ab4d8
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright Â© 2012 Intel Corporation
+ * Copyright Â© 2014 The Chromium OS Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#ifndef _VGEM_DRV_H_
+#define _VGEM_DRV_H_
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+
+#define to_vgem_bo(x) container_of(x, struct drm_vgem_gem_object, base)
+struct drm_vgem_gem_object {
+       struct drm_gem_object base;
+       struct page **pages;
+       bool use_dma_buf;
+};
+
+/* vgem_drv.c */
+extern void vgem_gem_put_pages(struct drm_vgem_gem_object *obj);
+extern int vgem_gem_get_pages(struct drm_vgem_gem_object *obj);
+
+/* vgem_dma_buf.c */
+extern struct sg_table *vgem_gem_prime_get_sg_table(
+                       struct drm_gem_object *gobj);
+extern int vgem_gem_prime_pin(struct drm_gem_object *gobj);
+extern void vgem_gem_prime_unpin(struct drm_gem_object *gobj);
+extern void *vgem_gem_prime_vmap(struct drm_gem_object *gobj);
+extern void vgem_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+extern struct drm_gem_object *vgem_gem_prime_import(struct drm_device *dev,
+                                                   struct dma_buf *dma_buf);
+
+
+#endif
index e13b9cb..620bb5c 100644 (file)
  */
 
 #define VMW_IOCTL_DEF(ioctl, func, flags) \
-  [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_##ioctl, flags, func, DRM_IOCTL_##ioctl}
+  [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_IOCTL_##ioctl, flags, func}
 
 /**
  * Ioctl definitions.
@@ -1044,7 +1044,7 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
                const struct drm_ioctl_desc *ioctl =
                        &vmw_ioctls[nr - DRM_COMMAND_BASE];
 
-               if (unlikely(ioctl->cmd_drv != cmd)) {
+               if (unlikely(ioctl->cmd != cmd)) {
                        DRM_ERROR("Invalid command format, ioctl %d\n",
                                  nr - DRM_COMMAND_BASE);
                        return -EINVAL;
index b10550e..6b7fdc1 100644 (file)
@@ -425,6 +425,12 @@ u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
 }
 EXPORT_SYMBOL(host1x_syncpt_read_min);
 
+u32 host1x_syncpt_read(struct host1x_syncpt *sp)
+{
+       return host1x_syncpt_load(sp);
+}
+EXPORT_SYMBOL(host1x_syncpt_read);
+
 int host1x_syncpt_nb_pts(struct host1x *host)
 {
        return host->info->nb_pts;
index 3ddfb3d..2970c6b 100644 (file)
@@ -441,8 +441,7 @@ static void ipu_di_config_clock(struct ipu_di *di,
 
                        in_rate = clk_get_rate(clk);
                        div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
-                       if (div == 0)
-                               div = 1;
+                       div = clamp(div, 1U, 255U);
 
                        clkgen0 = div << 4;
                }
@@ -459,8 +458,7 @@ static void ipu_di_config_clock(struct ipu_di *di,
 
                clkrate = clk_get_rate(di->clk_ipu);
                div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
-               if (div == 0)
-                       div = 1;
+               div = clamp(div, 1U, 255U);
                rate = clkrate / div;
 
                error = rate / (sig->mode.pixelclock / 1000);
@@ -483,8 +481,7 @@ static void ipu_di_config_clock(struct ipu_di *di,
 
                        in_rate = clk_get_rate(clk);
                        div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
-                       if (div == 0)
-                               div = 1;
+                       div = clamp(div, 1U, 255U);
 
                        clkgen0 = div << 4;
                }
index ad75588..1dcb96c 100644 (file)
@@ -297,8 +297,8 @@ static int calc_resize_coeffs(struct ipu_ic *ic,
                return -EINVAL;
        }
 
-       /* Cannot downsize more than 8:1 */
-       if ((out_size << 3) < in_size) {
+       /* Cannot downsize more than 4:1 */
+       if ((out_size << 2) < in_size) {
                dev_err(ipu->dev, "Unsupported downsize\n");
                return -EINVAL;
        }
index 7c669c3..56ce8c2 100644 (file)
@@ -1959,6 +1959,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_PRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
index 204312b..9c47867 100644 (file)
 #define USB_VENDOR_ID_LOGITECH         0x046d
 #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
 #define USB_DEVICE_ID_LOGITECH_T651    0xb00c
+#define USB_DEVICE_ID_LOGITECH_C077    0xc007
 #define USB_DEVICE_ID_LOGITECH_RECEIVER        0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
 #define USB_VENDOR_ID_TIVO             0x150a
 #define USB_DEVICE_ID_TIVO_SLIDE_BT    0x1200
 #define USB_DEVICE_ID_TIVO_SLIDE       0x1201
+#define USB_DEVICE_ID_TIVO_SLIDE_PRO   0x1203
 
 #define USB_VENDOR_ID_TOPSEED          0x0766
 #define USB_DEVICE_ID_TOPSEED_CYBERLINK        0x0204
index d790d8d..d986969 100644 (file)
@@ -64,6 +64,7 @@ static const struct hid_device_id tivo_devices[] = {
        /* TiVo Slide Bluetooth remote, pairs with a Broadcom dongle */
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_PRO) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, tivo_devices);
index 9be99a6..a821277 100644 (file)
@@ -78,6 +78,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS },
index 046351c..bbe32d6 100644 (file)
@@ -551,9 +551,13 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
           (features->type == CINTIQ && !(data[1] & 0x40)))
                return 1;
 
-       if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
+       if (wacom->shared) {
                wacom->shared->stylus_in_proximity = true;
 
+               if (wacom->shared->touch_down)
+                       return 1;
+       }
+
        /* in Range while exiting */
        if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) {
                input_report_key(input, BTN_TOUCH, 0);
@@ -1043,27 +1047,28 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
        struct input_dev *input = wacom->input;
        unsigned char *data = wacom->data;
        int i;
-       int current_num_contacts = 0;
+       int current_num_contacts = data[61];
        int contacts_to_send = 0;
        int num_contacts_left = 4; /* maximum contacts per packet */
        int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
        int y_offset = 2;
+       static int contact_with_no_pen_down_count = 0;
 
        if (wacom->features.type == WACOM_27QHDT) {
                current_num_contacts = data[63];
                num_contacts_left = 10;
                byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET;
                y_offset = 0;
-       } else {
-               current_num_contacts = data[61];
        }
 
        /*
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts)
+       if (current_num_contacts) {
                wacom->num_contacts_left = current_num_contacts;
+               contact_with_no_pen_down_count = 0;
+       }
 
        contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
 
@@ -1096,15 +1101,16 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
                                input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
                                input_report_abs(input, ABS_MT_ORIENTATION, w > h);
                        }
+                       contact_with_no_pen_down_count++;
                }
        }
        input_mt_report_pointer_emulation(input, true);
 
        wacom->num_contacts_left -= contacts_to_send;
-       if (wacom->num_contacts_left <= 0)
+       if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-
-       wacom->shared->touch_down = (wacom->num_contacts_left > 0);
+               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       }
        return 1;
 }
 
@@ -1116,6 +1122,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
        int current_num_contacts = data[2];
        int contacts_to_send = 0;
        int x_offset = 0;
+       static int contact_with_no_pen_down_count = 0;
 
        /* MTTPC does not support Height and Width */
        if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
@@ -1125,8 +1132,10 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts)
+       if (current_num_contacts) {
                wacom->num_contacts_left = current_num_contacts;
+               contact_with_no_pen_down_count = 0;
+       }
 
        /* There are at most 5 contacts per packet */
        contacts_to_send = min(5, wacom->num_contacts_left);
@@ -1147,15 +1156,16 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
                        int y = get_unaligned_le16(&data[offset + x_offset + 9]);
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       contact_with_no_pen_down_count++;
                }
        }
        input_mt_report_pointer_emulation(input, true);
 
        wacom->num_contacts_left -= contacts_to_send;
-       if (wacom->num_contacts_left < 0)
+       if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-
-       wacom->shared->touch_down = (wacom->num_contacts_left > 0);
+               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       }
        return 1;
 }
 
@@ -1193,29 +1203,25 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
 {
        unsigned char *data = wacom->data;
        struct input_dev *input = wacom->input;
-       bool prox;
+       bool prox = !wacom->shared->stylus_in_proximity;
        int x = 0, y = 0;
 
        if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
                return 0;
 
-       if (!wacom->shared->stylus_in_proximity) {
-               if (len == WACOM_PKGLEN_TPC1FG) {
-                       prox = data[0] & 0x01;
-                       x = get_unaligned_le16(&data[1]);
-                       y = get_unaligned_le16(&data[3]);
-               } else if (len == WACOM_PKGLEN_TPC1FG_B) {
-                       prox = data[2] & 0x01;
-                       x = get_unaligned_le16(&data[3]);
-                       y = get_unaligned_le16(&data[5]);
-               } else {
-                       prox = data[1] & 0x01;
-                       x = le16_to_cpup((__le16 *)&data[2]);
-                       y = le16_to_cpup((__le16 *)&data[4]);
-               }
-       } else
-               /* force touch out when pen is in prox */
-               prox = 0;
+       if (len == WACOM_PKGLEN_TPC1FG) {
+               prox = prox && (data[0] & 0x01);
+               x = get_unaligned_le16(&data[1]);
+               y = get_unaligned_le16(&data[3]);
+       } else if (len == WACOM_PKGLEN_TPC1FG_B) {
+               prox = prox && (data[2] & 0x01);
+               x = get_unaligned_le16(&data[3]);
+               y = get_unaligned_le16(&data[5]);
+       } else {
+               prox = prox && (data[1] & 0x01);
+               x = le16_to_cpup((__le16 *)&data[2]);
+               y = le16_to_cpup((__le16 *)&data[4]);
+       }
 
        if (prox) {
                input_report_abs(input, ABS_X, x);
@@ -1613,6 +1619,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
        struct input_dev *pad_input = wacom->pad_input;
        unsigned char *data = wacom->data;
        int i;
+       int contact_with_no_pen_down_count = 0;
 
        if (data[0] != 0x02)
            return 0;
@@ -1640,6 +1647,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
                        }
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       contact_with_no_pen_down_count++;
                }
        }
 
@@ -1649,11 +1657,12 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
        input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
        input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
        input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
+       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
        return 1;
 }
 
-static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
+static int wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data, int last_touch_count)
 {
        struct wacom_features *features = &wacom->features;
        struct input_dev *input = wacom->input;
@@ -1661,7 +1670,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
        int slot = input_mt_get_slot_by_key(input, data[0]);
 
        if (slot < 0)
-               return;
+               return 0;
 
        touch = touch && !wacom->shared->stylus_in_proximity;
 
@@ -1693,7 +1702,9 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
                input_report_abs(input, ABS_MT_POSITION_Y, y);
                input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
                input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
+               last_touch_count++;
        }
+       return last_touch_count;
 }
 
 static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
@@ -1718,6 +1729,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
        unsigned char *data = wacom->data;
        int count = data[1] & 0x07;
        int i;
+       int contact_with_no_pen_down_count = 0;
 
        if (data[0] != 0x02)
            return 0;
@@ -1728,12 +1740,15 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
                int msg_id = data[offset];
 
                if (msg_id >= 2 && msg_id <= 17)
-                       wacom_bpt3_touch_msg(wacom, data + offset);
+                       contact_with_no_pen_down_count = 
+                           wacom_bpt3_touch_msg(wacom, data + offset,
+                                                contact_with_no_pen_down_count);
                else if (msg_id == 128)
                        wacom_bpt3_button_msg(wacom, data + offset);
 
        }
        input_mt_report_pointer_emulation(input, true);
+       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
        return 1;
 }
@@ -1759,6 +1774,9 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
                return 0;
        }
 
+       if (wacom->shared->touch_down)
+               return 0;
+
        prox = (data[1] & 0x20) == 0x20;
 
        /*
index 1793aea..6eb738c 100644 (file)
@@ -1793,11 +1793,11 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
        tape->best_dsc_rw_freq = clamp_t(unsigned long, t, IDETAPE_DSC_RW_MIN,
                                         IDETAPE_DSC_RW_MAX);
        printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
-               "%lums tDSC%s\n",
+               "%ums tDSC%s\n",
                drive->name, tape->name, *(u16 *)&tape->caps[14],
                (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size,
                tape->buffer_size / 1024,
-               tape->best_dsc_rw_freq * 1000 / HZ,
+               jiffies_to_msecs(tape->best_dsc_rw_freq),
                (drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : "");
 
        ide_proc_register_driver(drive, tape->driver);
index 1096da3..75c6d21 100644 (file)
@@ -659,7 +659,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)
 
        mutex_lock(&data->mutex);
 
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = bma180_get_data_reg(data, bit);
                if (ret < 0) {
index 066d0c0..75567fd 100644 (file)
@@ -168,14 +168,14 @@ static const struct {
        int val;
        int val2;
        u8 bw_bits;
-} bmc150_accel_samp_freq_table[] = { {7, 810000, 0x08},
-                                    {15, 630000, 0x09},
-                                    {31, 250000, 0x0A},
-                                    {62, 500000, 0x0B},
-                                    {125, 0, 0x0C},
-                                    {250, 0, 0x0D},
-                                    {500, 0, 0x0E},
-                                    {1000, 0, 0x0F} };
+} bmc150_accel_samp_freq_table[] = { {15, 620000, 0x08},
+                                    {31, 260000, 0x09},
+                                    {62, 500000, 0x0A},
+                                    {125, 0, 0x0B},
+                                    {250, 0, 0x0C},
+                                    {500, 0, 0x0D},
+                                    {1000, 0, 0x0E},
+                                    {2000, 0, 0x0F} };
 
 static const struct {
        int bw_bits;
@@ -840,7 +840,7 @@ static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
 }
 
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
-               "7.810000 15.630000 31.250000 62.500000 125 250 500 1000");
+               "15.620000 31.260000 62.50000 125 250 500 1000 2000");
 
 static struct attribute *bmc150_accel_attributes[] = {
        &iio_const_attr_sampling_frequency_available.dev_attr.attr,
@@ -986,7 +986,7 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
        int bit, ret, i = 0;
 
        mutex_lock(&data->mutex);
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = i2c_smbus_read_word_data(data->client,
                                               BMC150_ACCEL_AXIS_TO_REG(bit));
index 567de26..1a63795 100644 (file)
@@ -956,7 +956,7 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
 
        mutex_lock(&data->mutex);
 
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = kxcjk1013_get_acc_reg(data, bit);
                if (ret < 0) {
index 202daf8..46379b1 100644 (file)
@@ -137,7 +137,8 @@ config AXP288_ADC
 
 config CC10001_ADC
        tristate "Cosmic Circuits 10001 ADC driver"
-       depends on HAS_IOMEM || HAVE_CLK || REGULATOR
+       depends on HAVE_CLK || REGULATOR
+       depends on HAS_IOMEM
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
index ff61ae5..8a0eb4a 100644 (file)
@@ -544,7 +544,6 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
 {
        struct iio_dev *idev = iio_trigger_get_drvdata(trig);
        struct at91_adc_state *st = iio_priv(idev);
-       struct iio_buffer *buffer = idev->buffer;
        struct at91_adc_reg_desc *reg = st->registers;
        u32 status = at91_adc_readl(st, reg->trigger_register);
        int value;
@@ -564,7 +563,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
                at91_adc_writel(st, reg->trigger_register,
                                status | value);
 
-               for_each_set_bit(bit, buffer->scan_mask,
+               for_each_set_bit(bit, idev->active_scan_mask,
                                 st->num_channels) {
                        struct iio_chan_spec const *chan = idev->channels + bit;
                        at91_adc_writel(st, AT91_ADC_CHER,
@@ -579,7 +578,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
                at91_adc_writel(st, reg->trigger_register,
                                status & ~value);
 
-               for_each_set_bit(bit, buffer->scan_mask,
+               for_each_set_bit(bit, idev->active_scan_mask,
                                 st->num_channels) {
                        struct iio_chan_spec const *chan = idev->channels + bit;
                        at91_adc_writel(st, AT91_ADC_CHDR,
index 2e5cc44..a0e7161 100644 (file)
@@ -188,12 +188,11 @@ static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
 static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
 {
        struct tiadc_device *adc_dev = iio_priv(indio_dev);
-       struct iio_buffer *buffer = indio_dev->buffer;
        unsigned int enb = 0;
        u8 bit;
 
        tiadc_step_config(indio_dev);
-       for_each_set_bit(bit, buffer->scan_mask, adc_dev->channels)
+       for_each_set_bit(bit, indio_dev->active_scan_mask, adc_dev->channels)
                enb |= (get_adc_step_bit(adc_dev, bit) << 1);
        adc_dev->buffer_en_ch_steps = enb;
 
index 8ec353c..e63b8e7 100644 (file)
@@ -141,9 +141,13 @@ struct vf610_adc {
        struct regulator *vref;
        struct vf610_adc_feature adc_feature;
 
+       u32 sample_freq_avail[5];
+
        struct completion completion;
 };
 
+static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
+
 #define VF610_ADC_CHAN(_idx, _chan_type) {                     \
        .type = (_chan_type),                                   \
        .indexed = 1,                                           \
@@ -180,35 +184,47 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = {
        /* sentinel */
 };
 
-/*
- * ADC sample frequency, unit is ADCK cycles.
- * ADC clk source is ipg clock, which is the same as bus clock.
- *
- * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder)
- * SFCAdder: fixed to 6 ADCK cycles
- * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
- * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
- * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
- *
- * By default, enable 12 bit resolution mode, clock source
- * set to ipg clock, So get below frequency group:
- */
-static const u32 vf610_sample_freq_avail[5] =
-{1941176, 559332, 286957, 145374, 73171};
+static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
+{
+       unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
+       int i;
+
+       /*
+        * Calculate ADC sample frequencies
+        * Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
+        * which is the same as bus clock.
+        *
+        * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder)
+        * SFCAdder: fixed to 6 ADCK cycles
+        * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
+        * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
+        * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
+        */
+       adck_rate = ipg_rate / info->adc_feature.clk_div;
+       for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
+               info->sample_freq_avail[i] =
+                       adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
+}
 
 static inline void vf610_adc_cfg_init(struct vf610_adc *info)
 {
+       struct vf610_adc_feature *adc_feature = &info->adc_feature;
+
        /* set default Configuration for ADC controller */
-       info->adc_feature.clk_sel = VF610_ADCIOC_BUSCLK_SET;
-       info->adc_feature.vol_ref = VF610_ADCIOC_VR_VREF_SET;
+       adc_feature->clk_sel = VF610_ADCIOC_BUSCLK_SET;
+       adc_feature->vol_ref = VF610_ADCIOC_VR_VREF_SET;
+
+       adc_feature->calibration = true;
+       adc_feature->ovwren = true;
+
+       adc_feature->res_mode = 12;
+       adc_feature->sample_rate = 1;
+       adc_feature->lpm = true;
 
-       info->adc_feature.calibration = true;
-       info->adc_feature.ovwren = true;
+       /* Use a save ADCK which is below 20MHz on all devices */
+       adc_feature->clk_div = 8;
 
-       info->adc_feature.clk_div = 1;
-       info->adc_feature.res_mode = 12;
-       info->adc_feature.sample_rate = 1;
-       info->adc_feature.lpm = true;
+       vf610_adc_calculate_rates(info);
 }
 
 static void vf610_adc_cfg_post_set(struct vf610_adc *info)
@@ -290,12 +306,10 @@ static void vf610_adc_cfg_set(struct vf610_adc *info)
 
        cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
 
-       /* low power configuration */
        cfg_data &= ~VF610_ADC_ADLPC_EN;
        if (adc_feature->lpm)
                cfg_data |= VF610_ADC_ADLPC_EN;
 
-       /* disable high speed */
        cfg_data &= ~VF610_ADC_ADHSC_EN;
 
        writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
@@ -435,10 +449,27 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1941176, 559332, 286957, 145374, 73171");
+static ssize_t vf610_show_samp_freq_avail(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct vf610_adc *info = iio_priv(dev_to_iio_dev(dev));
+       size_t len = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(info->sample_freq_avail); i++)
+               len += scnprintf(buf + len, PAGE_SIZE - len,
+                       "%u ", info->sample_freq_avail[i]);
+
+       /* replace trailing space by newline */
+       buf[len - 1] = '\n';
+
+       return len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(vf610_show_samp_freq_avail);
 
 static struct attribute *vf610_attributes[] = {
-       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
        NULL
 };
 
@@ -502,7 +533,7 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
                return IIO_VAL_FRACTIONAL_LOG2;
 
        case IIO_CHAN_INFO_SAMP_FREQ:
-               *val = vf610_sample_freq_avail[info->adc_feature.sample_rate];
+               *val = info->sample_freq_avail[info->adc_feature.sample_rate];
                *val2 = 0;
                return IIO_VAL_INT;
 
@@ -525,9 +556,9 @@ static int vf610_write_raw(struct iio_dev *indio_dev,
        switch (mask) {
                case IIO_CHAN_INFO_SAMP_FREQ:
                        for (i = 0;
-                               i < ARRAY_SIZE(vf610_sample_freq_avail);
+                               i < ARRAY_SIZE(info->sample_freq_avail);
                                i++)
-                               if (val == vf610_sample_freq_avail[i]) {
+                               if (val == info->sample_freq_avail[i]) {
                                        info->adc_feature.sample_rate = i;
                                        vf610_adc_sample_set(info);
                                        return 0;
index 60451b3..ccf3ea7 100644 (file)
@@ -822,7 +822,7 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p)
        int bit, ret, i = 0;
 
        mutex_lock(&data->mutex);
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = i2c_smbus_read_word_data(data->client,
                                               BMG160_AXIS_TO_REG(bit));
index e0017c2..f53e9a8 100644 (file)
@@ -60,7 +60,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
        iio_trigger_set_drvdata(adis->trig, adis);
        ret = iio_trigger_register(adis->trig);
 
-       indio_dev->trig = adis->trig;
+       indio_dev->trig = iio_trigger_get(adis->trig);
        if (ret)
                goto error_free_irq;
 
index d8d5bed..ef76afe 100644 (file)
@@ -410,42 +410,46 @@ error_read_raw:
        }
 }
 
-static int inv_mpu6050_write_fsr(struct inv_mpu6050_state *st, int fsr)
+static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val)
 {
-       int result;
+       int result, i;
        u8 d;
 
-       if (fsr < 0 || fsr > INV_MPU6050_MAX_GYRO_FS_PARAM)
-               return -EINVAL;
-       if (fsr == st->chip_config.fsr)
-               return 0;
+       for (i = 0; i < ARRAY_SIZE(gyro_scale_6050); ++i) {
+               if (gyro_scale_6050[i] == val) {
+                       d = (i << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
+                       result = inv_mpu6050_write_reg(st,
+                                       st->reg->gyro_config, d);
+                       if (result)
+                               return result;
 
-       d = (fsr << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
-       result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d);
-       if (result)
-               return result;
-       st->chip_config.fsr = fsr;
+                       st->chip_config.fsr = i;
+                       return 0;
+               }
+       }
 
-       return 0;
+       return -EINVAL;
 }
 
-static int inv_mpu6050_write_accel_fs(struct inv_mpu6050_state *st, int fs)
+static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val)
 {
-       int result;
+       int result, i;
        u8 d;
 
-       if (fs < 0 || fs > INV_MPU6050_MAX_ACCL_FS_PARAM)
-               return -EINVAL;
-       if (fs == st->chip_config.accl_fs)
-               return 0;
+       for (i = 0; i < ARRAY_SIZE(accel_scale); ++i) {
+               if (accel_scale[i] == val) {
+                       d = (i << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
+                       result = inv_mpu6050_write_reg(st,
+                                       st->reg->accl_config, d);
+                       if (result)
+                               return result;
 
-       d = (fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
-       result = inv_mpu6050_write_reg(st, st->reg->accl_config, d);
-       if (result)
-               return result;
-       st->chip_config.accl_fs = fs;
+                       st->chip_config.accl_fs = i;
+                       return 0;
+               }
+       }
 
-       return 0;
+       return -EINVAL;
 }
 
 static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
@@ -471,10 +475,10 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
        case IIO_CHAN_INFO_SCALE:
                switch (chan->type) {
                case IIO_ANGL_VEL:
-                       result = inv_mpu6050_write_fsr(st, val);
+                       result = inv_mpu6050_write_gyro_scale(st, val2);
                        break;
                case IIO_ACCEL:
-                       result = inv_mpu6050_write_accel_fs(st, val);
+                       result = inv_mpu6050_write_accel_scale(st, val2);
                        break;
                default:
                        result = -EINVAL;
index 0cd306a..ba27e27 100644 (file)
 #include <linux/poll.h>
 #include "inv_mpu_iio.h"
 
+static void inv_clear_kfifo(struct inv_mpu6050_state *st)
+{
+       unsigned long flags;
+
+       /* take the spin lock sem to avoid interrupt kick in */
+       spin_lock_irqsave(&st->time_stamp_lock, flags);
+       kfifo_reset(&st->timestamps);
+       spin_unlock_irqrestore(&st->time_stamp_lock, flags);
+}
+
 int inv_reset_fifo(struct iio_dev *indio_dev)
 {
        int result;
@@ -50,6 +60,10 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
                                        INV_MPU6050_BIT_FIFO_RST);
        if (result)
                goto reset_fifo_fail;
+
+       /* clear timestamps fifo */
+       inv_clear_kfifo(st);
+
        /* enable interrupt */
        if (st->chip_config.accl_fifo_enable ||
            st->chip_config.gyro_fifo_enable) {
@@ -83,16 +97,6 @@ reset_fifo_fail:
        return result;
 }
 
-static void inv_clear_kfifo(struct inv_mpu6050_state *st)
-{
-       unsigned long flags;
-
-       /* take the spin lock sem to avoid interrupt kick in */
-       spin_lock_irqsave(&st->time_stamp_lock, flags);
-       kfifo_reset(&st->timestamps);
-       spin_unlock_irqrestore(&st->time_stamp_lock, flags);
-}
-
 /**
  * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt.
  */
@@ -184,7 +188,6 @@ end_session:
 flush_fifo:
        /* Flush HW and SW FIFOs. */
        inv_reset_fifo(indio_dev);
-       inv_clear_kfifo(st);
        mutex_unlock(&indio_dev->mlock);
        iio_trigger_notify_done(indio_dev->trig);
 
index 5cc3692..b3a3637 100644 (file)
@@ -1227,7 +1227,7 @@ static irqreturn_t kmx61_trigger_handler(int irq, void *p)
                base = KMX61_MAG_XOUT_L;
 
        mutex_lock(&data->lock);
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = kmx61_read_measurement(data, base, bit);
                if (ret < 0) {
index aaba9d3..4df97f6 100644 (file)
@@ -847,8 +847,7 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
  * @attr_list: List of IIO device attributes
  *
  * This function frees the memory allocated for each of the IIO device
- * attributes in the list. Note: if you want to reuse the list after calling
- * this function you have to reinitialize it using INIT_LIST_HEAD().
+ * attributes in the list.
  */
 void iio_free_chan_devattr_list(struct list_head *attr_list)
 {
@@ -856,6 +855,7 @@ void iio_free_chan_devattr_list(struct list_head *attr_list)
 
        list_for_each_entry_safe(p, n, attr_list, l) {
                kfree(p->dev_attr.attr.name);
+               list_del(&p->l);
                kfree(p);
        }
 }
@@ -936,6 +936,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
 
        iio_free_chan_devattr_list(&indio_dev->channel_attr_list);
        kfree(indio_dev->chan_attr_group.attrs);
+       indio_dev->chan_attr_group.attrs = NULL;
 }
 
 static void iio_dev_release(struct device *device)
index a4b3970..a99692b 100644 (file)
@@ -500,6 +500,7 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
 error_free_setup_event_lines:
        iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
        kfree(indio_dev->event_interface);
+       indio_dev->event_interface = NULL;
        return ret;
 }
 
index 74dff4e..89fca3a 100644 (file)
@@ -494,7 +494,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private)
 
        mutex_lock(&data->mutex);
 
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = sx9500_read_proximity(data, &indio_dev->channels[bit],
                                            &val);
index aec7a6a..8c014b5 100644 (file)
@@ -99,6 +99,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
        if (dmasync)
                dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
 
+       /*
+        * If the combination of the addr and size requested for this memory
+        * region causes an integer overflow, return error.
+        */
+       if ((PAGE_ALIGN(addr + size) <= size) ||
+           (PAGE_ALIGN(addr + size) <= addr))
+               return ERR_PTR(-EINVAL);
+
        if (!can_do_mlock())
                return ERR_PTR(-EPERM);
 
index c761971..5904026 100644 (file)
@@ -64,6 +64,14 @@ enum {
 #define GUID_TBL_BLK_NUM_ENTRIES 8
 #define GUID_TBL_BLK_SIZE (GUID_TBL_ENTRY_SIZE * GUID_TBL_BLK_NUM_ENTRIES)
 
+/* Counters should be saturate once they reach their maximum value */
+#define ASSIGN_32BIT_COUNTER(counter, value) do {\
+       if ((value) > U32_MAX)                   \
+               counter = cpu_to_be32(U32_MAX); \
+       else                                     \
+               counter = cpu_to_be32(value);    \
+} while (0)
+
 struct mlx4_mad_rcv_buf {
        struct ib_grh grh;
        u8 payload[256];
@@ -806,10 +814,14 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
 static void edit_counter(struct mlx4_counter *cnt,
                                        struct ib_pma_portcounters *pma_cnt)
 {
-       pma_cnt->port_xmit_data = cpu_to_be32((be64_to_cpu(cnt->tx_bytes)>>2));
-       pma_cnt->port_rcv_data  = cpu_to_be32((be64_to_cpu(cnt->rx_bytes)>>2));
-       pma_cnt->port_xmit_packets = cpu_to_be32(be64_to_cpu(cnt->tx_frames));
-       pma_cnt->port_rcv_packets  = cpu_to_be32(be64_to_cpu(cnt->rx_frames));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data,
+                            (be64_to_cpu(cnt->tx_bytes) >> 2));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data,
+                            (be64_to_cpu(cnt->rx_bytes) >> 2));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets,
+                            be64_to_cpu(cnt->tx_frames));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets,
+                            be64_to_cpu(cnt->rx_frames));
 }
 
 static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
index ac6e2b7..b972c0b 100644 (file)
@@ -2697,8 +2697,12 @@ static void handle_bonded_port_state_event(struct work_struct *work)
        spin_lock_bh(&ibdev->iboe.lock);
        for (i = 0; i < MLX4_MAX_PORTS; ++i) {
                struct net_device *curr_netdev = ibdev->iboe.netdevs[i];
+               enum ib_port_state curr_port_state;
 
-               enum ib_port_state curr_port_state =
+               if (!curr_netdev)
+                       continue;
+
+               curr_port_state =
                        (netif_running(curr_netdev) &&
                         netif_carrier_ok(curr_netdev)) ?
                        IB_PORT_ACTIVE : IB_PORT_DOWN;
index 1bd15eb..27bcdbc 100644 (file)
@@ -1154,10 +1154,28 @@ out:
        mutex_unlock(&alps_mutex);
 }
 
-static void alps_report_bare_ps2_packet(struct input_dev *dev,
+static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
                                        unsigned char packet[],
                                        bool report_buttons)
 {
+       struct alps_data *priv = psmouse->private;
+       struct input_dev *dev;
+
+       /* Figure out which device to use to report the bare packet */
+       if (priv->proto_version == ALPS_PROTO_V2 &&
+           (priv->flags & ALPS_DUALPOINT)) {
+               /* On V2 devices the DualPoint Stick reports bare packets */
+               dev = priv->dev2;
+       } else if (unlikely(IS_ERR_OR_NULL(priv->dev3))) {
+               /* Register dev3 mouse if we received PS/2 packet first time */
+               if (!IS_ERR(priv->dev3))
+                       psmouse_queue_work(psmouse, &priv->dev3_register_work,
+                                          0);
+               return;
+       } else {
+               dev = priv->dev3;
+       }
+
        if (report_buttons)
                alps_report_buttons(dev, NULL,
                                packet[0] & 1, packet[0] & 2, packet[0] & 4);
@@ -1232,8 +1250,8 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
                 * de-synchronization.
                 */
 
-               alps_report_bare_ps2_packet(priv->dev2,
-                                           &psmouse->packet[3], false);
+               alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3],
+                                           false);
 
                /*
                 * Continue with the standard ALPS protocol handling,
@@ -1289,18 +1307,9 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
         * properly we only do this if the device is fully synchronized.
         */
        if (!psmouse->out_of_sync_cnt && (psmouse->packet[0] & 0xc8) == 0x08) {
-
-               /* Register dev3 mouse if we received PS/2 packet first time */
-               if (unlikely(!priv->dev3))
-                       psmouse_queue_work(psmouse,
-                                          &priv->dev3_register_work, 0);
-
                if (psmouse->pktcnt == 3) {
-                       /* Once dev3 mouse device is registered report data */
-                       if (likely(!IS_ERR_OR_NULL(priv->dev3)))
-                               alps_report_bare_ps2_packet(priv->dev3,
-                                                           psmouse->packet,
-                                                           true);
+                       alps_report_bare_ps2_packet(psmouse, psmouse->packet,
+                                                   true);
                        return PSMOUSE_FULL_PACKET;
                }
                return PSMOUSE_GOOD_DATA;
@@ -2281,10 +2290,12 @@ static int alps_set_protocol(struct psmouse *psmouse,
                priv->set_abs_params = alps_set_abs_params_mt;
                priv->nibble_commands = alps_v3_nibble_commands;
                priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
-               priv->x_max = 1360;
-               priv->y_max = 660;
                priv->x_bits = 23;
                priv->y_bits = 12;
+
+               if (alps_dolphin_get_device_area(psmouse, priv))
+                       return -EIO;
+
                break;
 
        case ALPS_PROTO_V6:
@@ -2303,9 +2314,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
                priv->set_abs_params = alps_set_abs_params_mt;
                priv->nibble_commands = alps_v3_nibble_commands;
                priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
-
-               if (alps_dolphin_get_device_area(psmouse, priv))
-                       return -EIO;
+               priv->x_max = 0xfff;
+               priv->y_max = 0x7ff;
 
                if (priv->fw_ver[1] != 0xba)
                        priv->flags |= ALPS_BUTTONPAD;
index f2cceb6..3b06c8a 100644 (file)
@@ -67,9 +67,6 @@
 #define X_MAX_POSITIVE 8176
 #define Y_MAX_POSITIVE 8176
 
-/* maximum ABS_MT_POSITION displacement (in mm) */
-#define DMAX 10
-
 /*****************************************************************************
  *     Stuff we need even when we do not want native Synaptics support
  ****************************************************************************/
@@ -123,32 +120,46 @@ void synaptics_reset(struct psmouse *psmouse)
 
 static bool cr48_profile_sensor;
 
+#define ANY_BOARD_ID 0
 struct min_max_quirk {
        const char * const *pnp_ids;
+       struct {
+               unsigned long int min, max;
+       } board_id;
        int x_min, x_max, y_min, y_max;
 };
 
 static const struct min_max_quirk min_max_pnpid_table[] = {
        {
                (const char * const []){"LEN0033", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1024, 5052, 2258, 4832
        },
        {
-               (const char * const []){"LEN0035", "LEN0042", NULL},
+               (const char * const []){"LEN0042", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1232, 5710, 1156, 4696
        },
        {
                (const char * const []){"LEN0034", "LEN0036", "LEN0037",
                                        "LEN0039", "LEN2002", "LEN2004",
                                        NULL},
+               {ANY_BOARD_ID, 2961},
                1024, 5112, 2024, 4832
        },
        {
                (const char * const []){"LEN2001", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1024, 5022, 2508, 4832
        },
        {
                (const char * const []){"LEN2006", NULL},
+               {2691, 2691},
+               1024, 5045, 2457, 4832
+       },
+       {
+               (const char * const []){"LEN2006", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1264, 5675, 1171, 4688
        },
        { }
@@ -175,9 +186,7 @@ static const char * const topbuttonpad_pnp_ids[] = {
        "LEN0041",
        "LEN0042", /* Yoga */
        "LEN0045",
-       "LEN0046",
        "LEN0047",
-       "LEN0048",
        "LEN0049",
        "LEN2000",
        "LEN2001", /* Edge E431 */
@@ -185,7 +194,7 @@ static const char * const topbuttonpad_pnp_ids[] = {
        "LEN2003",
        "LEN2004", /* L440 */
        "LEN2005",
-       "LEN2006",
+       "LEN2006", /* Edge E440/E540 */
        "LEN2007",
        "LEN2008",
        "LEN2009",
@@ -235,18 +244,39 @@ static int synaptics_model_id(struct psmouse *psmouse)
        return 0;
 }
 
+static int synaptics_more_extended_queries(struct psmouse *psmouse)
+{
+       struct synaptics_data *priv = psmouse->private;
+       unsigned char buf[3];
+
+       if (synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf))
+               return -1;
+
+       priv->ext_cap_10 = (buf[0]<<16) | (buf[1]<<8) | buf[2];
+
+       return 0;
+}
+
 /*
- * Read the board id from the touchpad
+ * Read the board id and the "More Extended Queries" from the touchpad
  * The board id is encoded in the "QUERY MODES" response
  */
-static int synaptics_board_id(struct psmouse *psmouse)
+static int synaptics_query_modes(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        unsigned char bid[3];
 
+       /* firmwares prior 7.5 have no board_id encoded */
+       if (SYN_ID_FULL(priv->identity) < 0x705)
+               return 0;
+
        if (synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid))
                return -1;
        priv->board_id = ((bid[0] & 0xfc) << 6) | bid[1];
+
+       if (SYN_MEXT_CAP_BIT(bid[0]))
+               return synaptics_more_extended_queries(psmouse);
+
        return 0;
 }
 
@@ -346,7 +376,6 @@ static int synaptics_resolution(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        unsigned char resp[3];
-       int i;
 
        if (SYN_ID_MAJOR(priv->identity) < 4)
                return 0;
@@ -358,17 +387,6 @@ static int synaptics_resolution(struct psmouse *psmouse)
                }
        }
 
-       for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
-               if (psmouse_matches_pnp_id(psmouse,
-                                          min_max_pnpid_table[i].pnp_ids)) {
-                       priv->x_min = min_max_pnpid_table[i].x_min;
-                       priv->x_max = min_max_pnpid_table[i].x_max;
-                       priv->y_min = min_max_pnpid_table[i].y_min;
-                       priv->y_max = min_max_pnpid_table[i].y_max;
-                       return 0;
-               }
-       }
-
        if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
            SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
                if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
@@ -377,23 +395,69 @@ static int synaptics_resolution(struct psmouse *psmouse)
                } else {
                        priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
                        priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
+                       psmouse_info(psmouse,
+                                    "queried max coordinates: x [..%d], y [..%d]\n",
+                                    priv->x_max, priv->y_max);
                }
        }
 
-       if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 &&
-           SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) {
+       if (SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c) &&
+           (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 ||
+            /*
+             * Firmware v8.1 does not report proper number of extended
+             * capabilities, but has been proven to report correct min
+             * coordinates.
+             */
+            SYN_ID_FULL(priv->identity) == 0x801)) {
                if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) {
                        psmouse_warn(psmouse,
                                     "device claims to have min coordinates query, but I'm not able to read it.\n");
                } else {
                        priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
                        priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
+                       psmouse_info(psmouse,
+                                    "queried min coordinates: x [%d..], y [%d..]\n",
+                                    priv->x_min, priv->y_min);
                }
        }
 
        return 0;
 }
 
+/*
+ * Apply quirk(s) if the hardware matches
+ */
+
+static void synaptics_apply_quirks(struct psmouse *psmouse)
+{
+       struct synaptics_data *priv = psmouse->private;
+       int i;
+
+       for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
+               if (!psmouse_matches_pnp_id(psmouse,
+                                           min_max_pnpid_table[i].pnp_ids))
+                       continue;
+
+               if (min_max_pnpid_table[i].board_id.min != ANY_BOARD_ID &&
+                   priv->board_id < min_max_pnpid_table[i].board_id.min)
+                       continue;
+
+               if (min_max_pnpid_table[i].board_id.max != ANY_BOARD_ID &&
+                   priv->board_id > min_max_pnpid_table[i].board_id.max)
+                       continue;
+
+               priv->x_min = min_max_pnpid_table[i].x_min;
+               priv->x_max = min_max_pnpid_table[i].x_max;
+               priv->y_min = min_max_pnpid_table[i].y_min;
+               priv->y_max = min_max_pnpid_table[i].y_max;
+               psmouse_info(psmouse,
+                            "quirked min/max coordinates: x [%d..%d], y [%d..%d]\n",
+                            priv->x_min, priv->x_max,
+                            priv->y_min, priv->y_max);
+               break;
+       }
+}
+
 static int synaptics_query_hardware(struct psmouse *psmouse)
 {
        if (synaptics_identify(psmouse))
@@ -402,13 +466,15 @@ static int synaptics_query_hardware(struct psmouse *psmouse)
                return -1;
        if (synaptics_firmware_id(psmouse))
                return -1;
-       if (synaptics_board_id(psmouse))
+       if (synaptics_query_modes(psmouse))
                return -1;
        if (synaptics_capability(psmouse))
                return -1;
        if (synaptics_resolution(psmouse))
                return -1;
 
+       synaptics_apply_quirks(psmouse);
+
        return 0;
 }
 
@@ -516,18 +582,22 @@ static int synaptics_is_pt_packet(unsigned char *buf)
        return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
 }
 
-static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
+static void synaptics_pass_pt_packet(struct psmouse *psmouse,
+                                    struct serio *ptport,
+                                    unsigned char *packet)
 {
+       struct synaptics_data *priv = psmouse->private;
        struct psmouse *child = serio_get_drvdata(ptport);
 
        if (child && child->state == PSMOUSE_ACTIVATED) {
-               serio_interrupt(ptport, packet[1], 0);
+               serio_interrupt(ptport, packet[1] | priv->pt_buttons, 0);
                serio_interrupt(ptport, packet[4], 0);
                serio_interrupt(ptport, packet[5], 0);
                if (child->pktsize == 4)
                        serio_interrupt(ptport, packet[2], 0);
-       } else
+       } else {
                serio_interrupt(ptport, packet[1], 0);
+       }
 }
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
@@ -605,6 +675,18 @@ static void synaptics_parse_agm(const unsigned char buf[],
        }
 }
 
+static void synaptics_parse_ext_buttons(const unsigned char buf[],
+                                       struct synaptics_data *priv,
+                                       struct synaptics_hw_state *hw)
+{
+       unsigned int ext_bits =
+               (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1;
+       unsigned int ext_mask = GENMASK(ext_bits - 1, 0);
+
+       hw->ext_buttons = buf[4] & ext_mask;
+       hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits;
+}
+
 static bool is_forcepad;
 
 static int synaptics_parse_hw_state(const unsigned char buf[],
@@ -691,28 +773,9 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
                        hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
                }
 
-               if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
+               if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 0 &&
                    ((buf[0] ^ buf[3]) & 0x02)) {
-                       switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
-                       default:
-                               /*
-                                * if nExtBtn is greater than 8 it should be
-                                * considered invalid and treated as 0
-                                */
-                               break;
-                       case 8:
-                               hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
-                       case 6:
-                               hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
-                       case 4:
-                               hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
-                       case 2:
-                               hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
-                       }
+                       synaptics_parse_ext_buttons(buf, priv, hw);
                }
        } else {
                hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
@@ -774,12 +837,54 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev,
        }
 }
 
+static void synaptics_report_ext_buttons(struct psmouse *psmouse,
+                                        const struct synaptics_hw_state *hw)
+{
+       struct input_dev *dev = psmouse->dev;
+       struct synaptics_data *priv = psmouse->private;
+       int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1;
+       char buf[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+       int i;
+
+       if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+               return;
+
+       /* Bug in FW 8.1, buttons are reported only when ExtBit is 1 */
+       if (SYN_ID_FULL(priv->identity) == 0x801 &&
+           !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02))
+               return;
+
+       if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) {
+               for (i = 0; i < ext_bits; i++) {
+                       input_report_key(dev, BTN_0 + 2 * i,
+                               hw->ext_buttons & (1 << i));
+                       input_report_key(dev, BTN_1 + 2 * i,
+                               hw->ext_buttons & (1 << (i + ext_bits)));
+               }
+               return;
+       }
+
+       /*
+        * This generation of touchpads has the trackstick buttons
+        * physically wired to the touchpad. Re-route them through
+        * the pass-through interface.
+        */
+       if (!priv->pt_port)
+               return;
+
+       /* The trackstick expects at most 3 buttons */
+       priv->pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons)      |
+                          SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 |
+                          SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2;
+
+       synaptics_pass_pt_packet(psmouse, priv->pt_port, buf);
+}
+
 static void synaptics_report_buttons(struct psmouse *psmouse,
                                     const struct synaptics_hw_state *hw)
 {
        struct input_dev *dev = psmouse->dev;
        struct synaptics_data *priv = psmouse->private;
-       int i;
 
        input_report_key(dev, BTN_LEFT, hw->left);
        input_report_key(dev, BTN_RIGHT, hw->right);
@@ -792,8 +897,7 @@ static void synaptics_report_buttons(struct psmouse *psmouse,
                input_report_key(dev, BTN_BACK, hw->down);
        }
 
-       for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
-               input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i));
+       synaptics_report_ext_buttons(psmouse, hw);
 }
 
 static void synaptics_report_mt_data(struct psmouse *psmouse,
@@ -813,7 +917,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse,
                pos[i].y = synaptics_invert_y(hw[i]->y);
        }
 
-       input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res);
+       input_mt_assign_slots(dev, slot, pos, nsemi, 0);
 
        for (i = 0; i < nsemi; i++) {
                input_mt_slot(dev, slot[i]);
@@ -1014,7 +1118,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
                if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
                    synaptics_is_pt_packet(psmouse->packet)) {
                        if (priv->pt_port)
-                               synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
+                               synaptics_pass_pt_packet(psmouse, priv->pt_port,
+                                                        psmouse->packet);
                } else
                        synaptics_process_packet(psmouse);
 
@@ -1116,8 +1221,9 @@ static void set_input_params(struct psmouse *psmouse,
                __set_bit(BTN_BACK, dev->keybit);
        }
 
-       for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
-               __set_bit(BTN_0 + i, dev->keybit);
+       if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10))
+               for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
+                       __set_bit(BTN_0 + i, dev->keybit);
 
        __clear_bit(EV_REL, dev->evbit);
        __clear_bit(REL_X, dev->relbit);
@@ -1125,7 +1231,8 @@ static void set_input_params(struct psmouse *psmouse,
 
        if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
                __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
-               if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids))
+               if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
+                   !SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10))
                        __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit);
                /* Clickpads report only left button */
                __clear_bit(BTN_RIGHT, dev->keybit);
index aedc329..ee4bd0d 100644 (file)
@@ -22,6 +22,7 @@
 #define SYN_QUE_EXT_CAPAB_0C           0x0c
 #define SYN_QUE_EXT_MAX_COORDS         0x0d
 #define SYN_QUE_EXT_MIN_COORDS         0x0f
+#define SYN_QUE_MEXT_CAPAB_10          0x10
 
 /* synatics modes */
 #define SYN_BIT_ABSOLUTE_MODE          (1 << 7)
@@ -53,6 +54,7 @@
 #define SYN_EXT_CAP_REQUESTS(c)                (((c) & 0x700000) >> 20)
 #define SYN_CAP_MULTI_BUTTON_NO(ec)    (((ec) & 0x00f000) >> 12)
 #define SYN_CAP_PRODUCT_ID(ec)         (((ec) & 0xff0000) >> 16)
+#define SYN_MEXT_CAP_BIT(m)            ((m) & (1 << 1))
 
 /*
  * The following describes response for the 0x0c query.
 #define SYN_CAP_REDUCED_FILTERING(ex0c)        ((ex0c) & 0x000400)
 #define SYN_CAP_IMAGE_SENSOR(ex0c)     ((ex0c) & 0x000800)
 
+/*
+ * The following descibes response for the 0x10 query.
+ *
+ * byte        mask    name                    meaning
+ * ----        ----    -------                 ------------
+ * 1   0x01    ext buttons are stick   buttons exported in the extended
+ *                                     capability are actually meant to be used
+ *                                     by the tracktick (pass-through).
+ * 1   0x02    SecurePad               the touchpad is a SecurePad, so it
+ *                                     contains a built-in fingerprint reader.
+ * 1   0xe0    more ext count          how many more extented queries are
+ *                                     available after this one.
+ * 2   0xff    SecurePad width         the width of the SecurePad fingerprint
+ *                                     reader.
+ * 3   0xff    SecurePad height        the height of the SecurePad fingerprint
+ *                                     reader.
+ */
+#define SYN_CAP_EXT_BUTTONS_STICK(ex10)        ((ex10) & 0x010000)
+#define SYN_CAP_SECUREPAD(ex10)                ((ex10) & 0x020000)
+
+#define SYN_CAP_EXT_BUTTON_STICK_L(eb) (!!((eb) & 0x01))
+#define SYN_CAP_EXT_BUTTON_STICK_M(eb) (!!((eb) & 0x02))
+#define SYN_CAP_EXT_BUTTON_STICK_R(eb) (!!((eb) & 0x04))
+
 /* synaptics modes query bits */
 #define SYN_MODE_ABSOLUTE(m)           ((m) & (1 << 7))
 #define SYN_MODE_RATE(m)               ((m) & (1 << 6))
@@ -143,6 +169,7 @@ struct synaptics_data {
        unsigned long int capabilities;         /* Capabilities */
        unsigned long int ext_cap;              /* Extended Capabilities */
        unsigned long int ext_cap_0c;           /* Ext Caps from 0x0c query */
+       unsigned long int ext_cap_10;           /* Ext Caps from 0x10 query */
        unsigned long int identity;             /* Identification */
        unsigned int x_res, y_res;              /* X/Y resolution in units/mm */
        unsigned int x_max, y_max;              /* Max coordinates (from FW) */
@@ -156,6 +183,7 @@ struct synaptics_data {
        bool disable_gesture;                   /* disable gestures */
 
        struct serio *pt_port;                  /* Pass-through serio port */
+       unsigned char pt_buttons;               /* Pass-through buttons */
 
        /*
         * Last received Advanced Gesture Mode (AGM) packet. An AGM packet
index fc13dd5..a3adde6 100644 (file)
@@ -1288,10 +1288,13 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
                return 0;
 
        spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
-       if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS)
+       if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS &&
+                       smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
                ret = arm_smmu_iova_to_phys_hard(domain, iova);
-       else
+       } else {
                ret = ops->iova_to_phys(ops, iova);
+       }
+
        spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
 
        return ret;
@@ -1556,7 +1559,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
                return -ENODEV;
        }
 
-       if (smmu->version == 1 || (!(id & ID0_ATOSNS) && (id & ID0_S1TS))) {
+       if ((id & ID0_S1TS) && ((smmu->version == 1) || (id & ID0_ATOSNS))) {
                smmu->features |= ARM_SMMU_FEAT_TRANS_OPS;
                dev_notice(smmu->dev, "\taddress translation ops\n");
        }
index ae4c1a8..2d1e05b 100644 (file)
@@ -1742,9 +1742,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
 
 static void domain_exit(struct dmar_domain *domain)
 {
-       struct dmar_drhd_unit *drhd;
-       struct intel_iommu *iommu;
        struct page *freelist = NULL;
+       int i;
 
        /* Domain 0 is reserved, so dont process it */
        if (!domain)
@@ -1764,8 +1763,8 @@ static void domain_exit(struct dmar_domain *domain)
 
        /* clear attached or cached domains */
        rcu_read_lock();
-       for_each_active_iommu(iommu, drhd)
-               iommu_detach_domain(domain, iommu);
+       for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus)
+               iommu_detach_domain(domain, g_iommus[i]);
        rcu_read_unlock();
 
        dma_free_pagelist(freelist);
index 10186ca..bc39bdf 100644 (file)
@@ -851,6 +851,7 @@ static int ipmmu_remove(struct platform_device *pdev)
 
 static const struct of_device_id ipmmu_of_ids[] = {
        { .compatible = "renesas,ipmmu-vmsa", },
+       { }
 };
 
 static struct platform_driver ipmmu_driver = {
index 596b0a9..9687f8a 100644 (file)
@@ -169,7 +169,7 @@ static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr)
 
 static void its_encode_devid(struct its_cmd_block *cmd, u32 devid)
 {
-       cmd->raw_cmd[0] &= ~(0xffffUL << 32);
+       cmd->raw_cmd[0] &= BIT_ULL(32) - 1;
        cmd->raw_cmd[0] |= ((u64)devid) << 32;
 }
 
@@ -802,6 +802,7 @@ static int its_alloc_tables(struct its_node *its)
        int i;
        int psz = SZ_64K;
        u64 shr = GITS_BASER_InnerShareable;
+       u64 cache = GITS_BASER_WaWb;
 
        for (i = 0; i < GITS_BASER_NR_REGS; i++) {
                u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
@@ -848,7 +849,7 @@ retry_baser:
                val = (virt_to_phys(base)                                |
                       (type << GITS_BASER_TYPE_SHIFT)                   |
                       ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) |
-                      GITS_BASER_WaWb                                   |
+                      cache                                             |
                       shr                                               |
                       GITS_BASER_VALID);
 
@@ -874,9 +875,12 @@ retry_baser:
                         * Shareability didn't stick. Just use
                         * whatever the read reported, which is likely
                         * to be the only thing this redistributor
-                        * supports.
+                        * supports. If that's zero, make it
+                        * non-cacheable as well.
                         */
                        shr = tmp & GITS_BASER_SHAREABILITY_MASK;
+                       if (!shr)
+                               cache = GITS_BASER_nC;
                        goto retry_baser;
                }
 
@@ -980,16 +984,39 @@ static void its_cpu_init_lpis(void)
        tmp = readq_relaxed(rbase + GICR_PROPBASER);
 
        if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) {
+               if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) {
+                       /*
+                        * The HW reports non-shareable, we must
+                        * remove the cacheability attributes as
+                        * well.
+                        */
+                       val &= ~(GICR_PROPBASER_SHAREABILITY_MASK |
+                                GICR_PROPBASER_CACHEABILITY_MASK);
+                       val |= GICR_PROPBASER_nC;
+                       writeq_relaxed(val, rbase + GICR_PROPBASER);
+               }
                pr_info_once("GIC: using cache flushing for LPI property table\n");
                gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING;
        }
 
        /* set PENDBASE */
        val = (page_to_phys(pend_page) |
-              GICR_PROPBASER_InnerShareable |
-              GICR_PROPBASER_WaWb);
+              GICR_PENDBASER_InnerShareable |
+              GICR_PENDBASER_WaWb);
 
        writeq_relaxed(val, rbase + GICR_PENDBASER);
+       tmp = readq_relaxed(rbase + GICR_PENDBASER);
+
+       if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) {
+               /*
+                * The HW reports non-shareable, we must remove the
+                * cacheability attributes as well.
+                */
+               val &= ~(GICR_PENDBASER_SHAREABILITY_MASK |
+                        GICR_PENDBASER_CACHEABILITY_MASK);
+               val |= GICR_PENDBASER_nC;
+               writeq_relaxed(val, rbase + GICR_PENDBASER);
+       }
 
        /* Enable LPIs */
        val = readl_relaxed(rbase + GICR_CTLR);
@@ -1026,7 +1053,7 @@ static void its_cpu_init_collection(void)
                         * This ITS wants a linear CPU number.
                         */
                        target = readq_relaxed(gic_data_rdist_rd_base() + GICR_TYPER);
-                       target = GICR_TYPER_CPU_NUMBER(target);
+                       target = GICR_TYPER_CPU_NUMBER(target) << 16;
                }
 
                /* Perform collection mapping */
@@ -1422,14 +1449,26 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
 
        writeq_relaxed(baser, its->base + GITS_CBASER);
        tmp = readq_relaxed(its->base + GITS_CBASER);
-       writeq_relaxed(0, its->base + GITS_CWRITER);
-       writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
 
-       if ((tmp ^ baser) & GITS_BASER_SHAREABILITY_MASK) {
+       if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) {
+               if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) {
+                       /*
+                        * The HW reports non-shareable, we must
+                        * remove the cacheability attributes as
+                        * well.
+                        */
+                       baser &= ~(GITS_CBASER_SHAREABILITY_MASK |
+                                  GITS_CBASER_CACHEABILITY_MASK);
+                       baser |= GITS_CBASER_nC;
+                       writeq_relaxed(baser, its->base + GITS_CBASER);
+               }
                pr_info("ITS: using cache flushing for cmd queue\n");
                its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING;
        }
 
+       writeq_relaxed(0, its->base + GITS_CWRITER);
+       writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
+
        if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) {
                its->domain = irq_domain_add_tree(NULL, &its_domain_ops, its);
                if (!its->domain) {
index 6a7447c..358a574 100644 (file)
@@ -1609,7 +1609,7 @@ icn_setup(char *line)
        if (ints[0] > 1)
                membase = (unsigned long)ints[2];
        if (str && *str) {
-               strcpy(sid, str);
+               strlcpy(sid, str, sizeof(sid));
                icn_id = sid;
                if ((p = strchr(sid, ','))) {
                        *p++ = 0;
index ee035ec..169172d 100644 (file)
@@ -1,6 +1,6 @@
 config LGUEST
        tristate "Linux hypervisor example code"
-       depends on X86_32 && EVENTFD && TTY
+       depends on X86_32 && EVENTFD && TTY && PCI_DIRECT
        select HVC_DRIVER
        ---help---
          This is a very simple module which allows you to run
index 37de017..74adcd2 100644 (file)
@@ -289,9 +289,16 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
        struct request_queue *q = bdev_get_queue(where->bdev);
        unsigned short logical_block_size = queue_logical_block_size(q);
        sector_t num_sectors;
+       unsigned int uninitialized_var(special_cmd_max_sectors);
 
-       /* Reject unsupported discard requests */
-       if ((rw & REQ_DISCARD) && !blk_queue_discard(q)) {
+       /*
+        * Reject unsupported discard and write same requests.
+        */
+       if (rw & REQ_DISCARD)
+               special_cmd_max_sectors = q->limits.max_discard_sectors;
+       else if (rw & REQ_WRITE_SAME)
+               special_cmd_max_sectors = q->limits.max_write_same_sectors;
+       if ((rw & (REQ_DISCARD | REQ_WRITE_SAME)) && special_cmd_max_sectors == 0) {
                dec_count(io, region, -EOPNOTSUPP);
                return;
        }
@@ -317,7 +324,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                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);
+                       num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining);
                        bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
                        remaining -= num_sectors;
                } else if (rw & REQ_WRITE_SAME) {
@@ -326,7 +333,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);
+                       num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining);
                        bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
 
                        offset = 0;
index 8b204ae..f83a0f3 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/log2.h>
 #include <linux/dm-kcopyd.h>
 
+#include "dm.h"
+
 #include "dm-exception-store.h"
 
 #define DM_MSG_PREFIX "snapshots"
@@ -291,12 +293,23 @@ struct origin {
 };
 
 /*
+ * This structure is allocated for each origin target
+ */
+struct dm_origin {
+       struct dm_dev *dev;
+       struct dm_target *ti;
+       unsigned split_boundary;
+       struct list_head hash_list;
+};
+
+/*
  * Size of the hash table for origin volumes. If we make this
  * the size of the minors list then it should be nearly perfect
  */
 #define ORIGIN_HASH_SIZE 256
 #define ORIGIN_MASK      0xFF
 static struct list_head *_origins;
+static struct list_head *_dm_origins;
 static struct rw_semaphore _origins_lock;
 
 static DECLARE_WAIT_QUEUE_HEAD(_pending_exceptions_done);
@@ -310,12 +323,22 @@ static int init_origin_hash(void)
        _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
                           GFP_KERNEL);
        if (!_origins) {
-               DMERR("unable to allocate memory");
+               DMERR("unable to allocate memory for _origins");
                return -ENOMEM;
        }
-
        for (i = 0; i < ORIGIN_HASH_SIZE; i++)
                INIT_LIST_HEAD(_origins + i);
+
+       _dm_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
+                             GFP_KERNEL);
+       if (!_dm_origins) {
+               DMERR("unable to allocate memory for _dm_origins");
+               kfree(_origins);
+               return -ENOMEM;
+       }
+       for (i = 0; i < ORIGIN_HASH_SIZE; i++)
+               INIT_LIST_HEAD(_dm_origins + i);
+
        init_rwsem(&_origins_lock);
 
        return 0;
@@ -324,6 +347,7 @@ static int init_origin_hash(void)
 static void exit_origin_hash(void)
 {
        kfree(_origins);
+       kfree(_dm_origins);
 }
 
 static unsigned origin_hash(struct block_device *bdev)
@@ -350,6 +374,30 @@ static void __insert_origin(struct origin *o)
        list_add_tail(&o->hash_list, sl);
 }
 
+static struct dm_origin *__lookup_dm_origin(struct block_device *origin)
+{
+       struct list_head *ol;
+       struct dm_origin *o;
+
+       ol = &_dm_origins[origin_hash(origin)];
+       list_for_each_entry (o, ol, hash_list)
+               if (bdev_equal(o->dev->bdev, origin))
+                       return o;
+
+       return NULL;
+}
+
+static void __insert_dm_origin(struct dm_origin *o)
+{
+       struct list_head *sl = &_dm_origins[origin_hash(o->dev->bdev)];
+       list_add_tail(&o->hash_list, sl);
+}
+
+static void __remove_dm_origin(struct dm_origin *o)
+{
+       list_del(&o->hash_list);
+}
+
 /*
  * _origins_lock must be held when calling this function.
  * Returns number of snapshots registered using the supplied cow device, plus:
@@ -1840,9 +1888,40 @@ static int snapshot_preresume(struct dm_target *ti)
 static void snapshot_resume(struct dm_target *ti)
 {
        struct dm_snapshot *s = ti->private;
-       struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
+       struct dm_snapshot *snap_src = NULL, *snap_dest = NULL, *snap_merging = NULL;
+       struct dm_origin *o;
+       struct mapped_device *origin_md = NULL;
+       bool must_restart_merging = false;
 
        down_read(&_origins_lock);
+
+       o = __lookup_dm_origin(s->origin->bdev);
+       if (o)
+               origin_md = dm_table_get_md(o->ti->table);
+       if (!origin_md) {
+               (void) __find_snapshots_sharing_cow(s, NULL, NULL, &snap_merging);
+               if (snap_merging)
+                       origin_md = dm_table_get_md(snap_merging->ti->table);
+       }
+       if (origin_md == dm_table_get_md(ti->table))
+               origin_md = NULL;
+       if (origin_md) {
+               if (dm_hold(origin_md))
+                       origin_md = NULL;
+       }
+
+       up_read(&_origins_lock);
+
+       if (origin_md) {
+               dm_internal_suspend_fast(origin_md);
+               if (snap_merging && test_bit(RUNNING_MERGE, &snap_merging->state_bits)) {
+                       must_restart_merging = true;
+                       stop_merge(snap_merging);
+               }
+       }
+
+       down_read(&_origins_lock);
+
        (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
        if (snap_src && snap_dest) {
                down_write(&snap_src->lock);
@@ -1851,8 +1930,16 @@ static void snapshot_resume(struct dm_target *ti)
                up_write(&snap_dest->lock);
                up_write(&snap_src->lock);
        }
+
        up_read(&_origins_lock);
 
+       if (origin_md) {
+               if (must_restart_merging)
+                       start_merge(snap_merging);
+               dm_internal_resume_fast(origin_md);
+               dm_put(origin_md);
+       }
+
        /* Now we have correct chunk size, reregister */
        reregister_snapshot(s);
 
@@ -2133,11 +2220,6 @@ static int origin_write_extent(struct dm_snapshot *merging_snap,
  * Origin: maps a linear range of a device, with hooks for snapshotting.
  */
 
-struct dm_origin {
-       struct dm_dev *dev;
-       unsigned split_boundary;
-};
-
 /*
  * Construct an origin mapping: <dev_path>
  * The context for an origin is merely a 'struct dm_dev *'
@@ -2166,6 +2248,7 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad_open;
        }
 
+       o->ti = ti;
        ti->private = o;
        ti->num_flush_bios = 1;
 
@@ -2180,6 +2263,7 @@ bad_alloc:
 static void origin_dtr(struct dm_target *ti)
 {
        struct dm_origin *o = ti->private;
+
        dm_put_device(ti, o->dev);
        kfree(o);
 }
@@ -2216,6 +2300,19 @@ static void origin_resume(struct dm_target *ti)
        struct dm_origin *o = ti->private;
 
        o->split_boundary = get_origin_minimum_chunksize(o->dev->bdev);
+
+       down_write(&_origins_lock);
+       __insert_dm_origin(o);
+       up_write(&_origins_lock);
+}
+
+static void origin_postsuspend(struct dm_target *ti)
+{
+       struct dm_origin *o = ti->private;
+
+       down_write(&_origins_lock);
+       __remove_dm_origin(o);
+       up_write(&_origins_lock);
 }
 
 static void origin_status(struct dm_target *ti, status_type_t type,
@@ -2258,12 +2355,13 @@ static int origin_iterate_devices(struct dm_target *ti,
 
 static struct target_type origin_target = {
        .name    = "snapshot-origin",
-       .version = {1, 8, 1},
+       .version = {1, 9, 0},
        .module  = THIS_MODULE,
        .ctr     = origin_ctr,
        .dtr     = origin_dtr,
        .map     = origin_map,
        .resume  = origin_resume,
+       .postsuspend = origin_postsuspend,
        .status  = origin_status,
        .merge   = origin_merge,
        .iterate_devices = origin_iterate_devices,
@@ -2271,7 +2369,7 @@ static struct target_type origin_target = {
 
 static struct target_type snapshot_target = {
        .name    = "snapshot",
-       .version = {1, 12, 0},
+       .version = {1, 13, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
@@ -2285,7 +2383,7 @@ static struct target_type snapshot_target = {
 
 static struct target_type merge_target = {
        .name    = dm_snapshot_merge_target_name,
-       .version = {1, 2, 0},
+       .version = {1, 3, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
index 654773c..921aafd 100644 (file)
@@ -2358,17 +2358,6 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_REMAPPED;
 
        case -ENODATA:
-               if (get_pool_mode(tc->pool) == PM_READ_ONLY) {
-                       /*
-                        * This block isn't provisioned, and we have no way
-                        * of doing so.
-                        */
-                       handle_unserviceable_bio(tc->pool, bio);
-                       cell_defer_no_holder(tc, virt_cell);
-                       return DM_MAPIO_SUBMITTED;
-               }
-               /* fall through */
-
        case -EWOULDBLOCK:
                thin_defer_cell(tc, virt_cell);
                return DM_MAPIO_SUBMITTED;
index 73f2880..8001fe9 100644 (file)
@@ -433,7 +433,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode)
 
        dm_get(md);
        atomic_inc(&md->open_count);
-
 out:
        spin_unlock(&_minor_lock);
 
@@ -442,16 +441,20 @@ out:
 
 static void dm_blk_close(struct gendisk *disk, fmode_t mode)
 {
-       struct mapped_device *md = disk->private_data;
+       struct mapped_device *md;
 
        spin_lock(&_minor_lock);
 
+       md = disk->private_data;
+       if (WARN_ON(!md))
+               goto out;
+
        if (atomic_dec_and_test(&md->open_count) &&
            (test_bit(DMF_DEFERRED_REMOVE, &md->flags)))
                queue_work(deferred_remove_workqueue, &deferred_remove_work);
 
        dm_put(md);
-
+out:
        spin_unlock(&_minor_lock);
 }
 
@@ -2241,7 +2244,6 @@ static void free_dev(struct mapped_device *md)
        int minor = MINOR(disk_devt(md->disk));
 
        unlock_fs(md);
-       bdput(md->bdev);
        destroy_workqueue(md->wq);
 
        if (md->kworker_task)
@@ -2252,19 +2254,22 @@ static void free_dev(struct mapped_device *md)
                mempool_destroy(md->rq_pool);
        if (md->bs)
                bioset_free(md->bs);
-       blk_integrity_unregister(md->disk);
-       del_gendisk(md->disk);
+
        cleanup_srcu_struct(&md->io_barrier);
        free_table_devices(&md->table_devices);
-       free_minor(minor);
+       dm_stats_cleanup(&md->stats);
 
        spin_lock(&_minor_lock);
        md->disk->private_data = NULL;
        spin_unlock(&_minor_lock);
-
+       if (blk_get_integrity(md->disk))
+               blk_integrity_unregister(md->disk);
+       del_gendisk(md->disk);
        put_disk(md->disk);
        blk_cleanup_queue(md->queue);
-       dm_stats_cleanup(&md->stats);
+       bdput(md->bdev);
+       free_minor(minor);
+
        module_put(THIS_MODULE);
        kfree(md);
 }
@@ -2616,6 +2621,19 @@ void dm_get(struct mapped_device *md)
        BUG_ON(test_bit(DMF_FREEING, &md->flags));
 }
 
+int dm_hold(struct mapped_device *md)
+{
+       spin_lock(&_minor_lock);
+       if (test_bit(DMF_FREEING, &md->flags)) {
+               spin_unlock(&_minor_lock);
+               return -EBUSY;
+       }
+       dm_get(md);
+       spin_unlock(&_minor_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dm_hold);
+
 const char *dm_device_name(struct mapped_device *md)
 {
        return md->name;
@@ -2629,8 +2647,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
 
        might_sleep();
 
-       spin_lock(&_minor_lock);
        map = dm_get_live_table(md, &srcu_idx);
+
+       spin_lock(&_minor_lock);
        idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md))));
        set_bit(DMF_FREEING, &md->flags);
        spin_unlock(&_minor_lock);
@@ -2638,10 +2657,16 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
        if (dm_request_based(md))
                flush_kthread_worker(&md->kworker);
 
+       /*
+        * Take suspend_lock so that presuspend and postsuspend methods
+        * do not race with internal suspend.
+        */
+       mutex_lock(&md->suspend_lock);
        if (!dm_suspended_md(md)) {
                dm_table_presuspend_targets(map);
                dm_table_postsuspend_targets(map);
        }
+       mutex_unlock(&md->suspend_lock);
 
        /* dm_put_live_table must be before msleep, otherwise deadlock is possible */
        dm_put_live_table(md, srcu_idx);
@@ -3115,6 +3140,7 @@ void dm_internal_suspend_fast(struct mapped_device *md)
        flush_workqueue(md->wq);
        dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
 }
+EXPORT_SYMBOL_GPL(dm_internal_suspend_fast);
 
 void dm_internal_resume_fast(struct mapped_device *md)
 {
@@ -3126,6 +3152,7 @@ void dm_internal_resume_fast(struct mapped_device *md)
 done:
        mutex_unlock(&md->suspend_lock);
 }
+EXPORT_SYMBOL_GPL(dm_internal_resume_fast);
 
 /*-----------------------------------------------------------------
  * Event notification.
index cadf9cc..717daad 100644 (file)
@@ -5080,7 +5080,8 @@ int md_run(struct mddev *mddev)
        }
        if (err) {
                mddev_detach(mddev);
-               pers->free(mddev, mddev->private);
+               if (mddev->private)
+                       pers->free(mddev, mddev->private);
                module_put(pers->owner);
                bitmap_destroy(mddev);
                return err;
index a13f738..3ed9f42 100644 (file)
@@ -467,8 +467,6 @@ static int raid0_run(struct mddev *mddev)
        dump_zones(mddev);
 
        ret = md_integrity_register(mddev);
-       if (ret)
-               raid0_free(mddev, conf);
 
        return ret;
 }
index 56a5cb0..0d07fca 100644 (file)
@@ -2504,7 +2504,6 @@ vpfe_get_pdata(struct platform_device *pdev)
                                             GFP_KERNEL);
                pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_OF;
                pdata->asd[i]->match.of.node = rem;
-               of_node_put(endpoint);
                of_node_put(rem);
        }
 
index cee7b56..f2a3d96 100644 (file)
@@ -1694,7 +1694,6 @@ static void scan_of_host(struct soc_camera_host *ici)
                if (!i)
                        soc_of_bind(ici, epn, ren->parent);
 
-               of_node_put(epn);
                of_node_put(ren);
 
                if (i) {
@@ -1702,6 +1701,8 @@ static void scan_of_host(struct soc_camera_host *ici)
                        break;
                }
        }
+
+       of_node_put(epn);
 }
 
 #else
index f38ec42..5615522 100644 (file)
@@ -739,7 +739,7 @@ static int __init kempld_init(void)
                for (id = kempld_dmi_table;
                     id->matches[0].slot != DMI_NONE; id++)
                        if (strstr(id->ident, force_device_id))
-                               if (id->callback && id->callback(id))
+                               if (id->callback && !id->callback(id))
                                        break;
                if (id->matches[0].slot == DMI_NONE)
                        return -ENODEV;
index ede5024..dbd907d 100644 (file)
@@ -196,18 +196,27 @@ EXPORT_SYMBOL_GPL(rtsx_usb_ep0_write_register);
 int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
 {
        u16 value;
+       u8 *buf;
+       int ret;
 
        if (!data)
                return -EINVAL;
-       *data = 0;
+
+       buf = kzalloc(sizeof(u8), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        addr |= EP0_READ_REG_CMD << EP0_OP_SHIFT;
        value = swab16(addr);
 
-       return usb_control_msg(ucr->pusb_dev,
+       ret = usb_control_msg(ucr->pusb_dev,
                        usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value, 0, data, 1, 100);
+                       value, 0, buf, 1, 100);
+       *data = *buf;
+
+       kfree(buf);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(rtsx_usb_ep0_read_register);
 
@@ -288,18 +297,27 @@ static int rtsx_usb_get_status_with_bulk(struct rtsx_ucr *ucr, u16 *status)
 int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status)
 {
        int ret;
+       u16 *buf;
 
        if (!status)
                return -EINVAL;
 
-       if (polling_pipe == 0)
+       if (polling_pipe == 0) {
+               buf = kzalloc(sizeof(u16), GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+
                ret = usb_control_msg(ucr->pusb_dev,
                                usb_rcvctrlpipe(ucr->pusb_dev, 0),
                                RTSX_USB_REQ_POLL,
                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               0, 0, status, 2, 100);
-       else
+                               0, 0, buf, 2, 100);
+               *status = *buf;
+
+               kfree(buf);
+       } else {
                ret = rtsx_usb_get_status_with_bulk(ucr, status);
+       }
 
        /* usb_control_msg may return positive when success */
        if (ret < 0)
index e9f1d8d..c53f14a 100644 (file)
@@ -124,7 +124,7 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
                    PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) {
                        ret = PTR_ERR(pwrseq->reset_gpios[i]);
 
-                       while (--i)
+                       while (i--)
                                gpiod_put(pwrseq->reset_gpios[i]);
 
                        goto clk_put;
index da4c792..16e34b3 100644 (file)
@@ -425,9 +425,10 @@ retry:
                                        ubi_warn(ubi, "corrupted VID header at PEB %d, LEB %d:%d",
                                                 pnum, vol_id, lnum);
                                        err = -EBADMSG;
-                               } else
+                               } else {
                                        err = -EINVAL;
                                        ubi_ro_mode(ubi);
+                               }
                        }
                        goto out_free;
                } else if (err == UBI_IO_BITFLIPS)
index b979c26..089a402 100644 (file)
@@ -3850,7 +3850,8 @@ static inline int bond_slave_override(struct bonding *bond,
        /* Find out if any slaves have the same mapping as this skb. */
        bond_for_each_slave_rcu(bond, slave, iter) {
                if (slave->queue_id == skb->queue_mapping) {
-                       if (bond_slave_can_tx(slave)) {
+                       if (bond_slave_is_up(slave) &&
+                           slave->link == BOND_LINK_UP) {
                                bond_dev_queue_xmit(bond, skb, slave->dev);
                                return 0;
                        }
index 98d73aa..58808f6 100644 (file)
@@ -131,7 +131,7 @@ config CAN_RCAR
 
 config CAN_XILINXCAN
        tristate "Xilinx CAN"
-       depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
+       depends on ARCH_ZYNQ || ARM64 || MICROBLAZE || COMPILE_TEST
        depends on COMMON_CLK && HAS_IOMEM
        ---help---
          Xilinx CAN driver. This driver supports both soft AXI CAN IP and
index 80c46ad..ad0a7e8 100644 (file)
@@ -592,13 +592,12 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
                rx_state = unlikely(reg_esr & FLEXCAN_ESR_RX_WRN) ?
                           CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE;
                new_state = max(tx_state, rx_state);
-       } else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE)) {
+       } else {
                __flexcan_get_berr_counter(dev, &bec);
-               new_state = CAN_STATE_ERROR_PASSIVE;
+               new_state = flt == FLEXCAN_ESR_FLT_CONF_PASSIVE ?
+                           CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF;
                rx_state = bec.rxerr >= bec.txerr ? new_state : 0;
                tx_state = bec.rxerr <= bec.txerr ? new_state : 0;
-       } else {
-               new_state = CAN_STATE_BUS_OFF;
        }
 
        /* state hasn't changed */
@@ -1158,12 +1157,19 @@ static int flexcan_probe(struct platform_device *pdev)
        const struct flexcan_devtype_data *devtype_data;
        struct net_device *dev;
        struct flexcan_priv *priv;
+       struct regulator *reg_xceiver;
        struct resource *mem;
        struct clk *clk_ipg = NULL, *clk_per = NULL;
        void __iomem *base;
        int err, irq;
        u32 clock_freq = 0;
 
+       reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
+       if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       else if (IS_ERR(reg_xceiver))
+               reg_xceiver = NULL;
+
        if (pdev->dev.of_node)
                of_property_read_u32(pdev->dev.of_node,
                                                "clock-frequency", &clock_freq);
@@ -1224,9 +1230,7 @@ static int flexcan_probe(struct platform_device *pdev)
        priv->pdata = dev_get_platdata(&pdev->dev);
        priv->devtype_data = devtype_data;
 
-       priv->reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
-       if (IS_ERR(priv->reg_xceiver))
-               priv->reg_xceiver = NULL;
+       priv->reg_xceiver = reg_xceiver;
 
        netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);
 
index 009acc8..8b4d3e6 100644 (file)
@@ -901,6 +901,8 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *
        }
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
        init_usb_anchor(&dev->rx_submitted);
 
        atomic_set(&dev->active_channels, 0);
index a316fa4..57611fd 100644 (file)
@@ -14,6 +14,7 @@
  * Copyright (C) 2015 Valeo S.A.
  */
 
+#include <linux/spinlock.h>
 #include <linux/kernel.h>
 #include <linux/completion.h>
 #include <linux/module.h>
@@ -24,7 +25,6 @@
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
-#define MAX_TX_URBS                    16
 #define MAX_RX_URBS                    4
 #define START_TIMEOUT                  1000 /* msecs */
 #define STOP_TIMEOUT                   1000 /* msecs */
@@ -442,6 +442,7 @@ struct kvaser_usb_error_summary {
        };
 };
 
+/* Context for an outstanding, not yet ACKed, transmission */
 struct kvaser_usb_tx_urb_context {
        struct kvaser_usb_net_priv *priv;
        u32 echo_index;
@@ -455,8 +456,13 @@ struct kvaser_usb {
        struct usb_endpoint_descriptor *bulk_in, *bulk_out;
        struct usb_anchor rx_submitted;
 
+       /* @max_tx_urbs: Firmware-reported maximum number of oustanding,
+        * not yet ACKed, transmissions on this device. This value is
+        * also used as a sentinel for marking free tx contexts.
+        */
        u32 fw_version;
        unsigned int nchannels;
+       unsigned int max_tx_urbs;
        enum kvaser_usb_family family;
 
        bool rxinitdone;
@@ -466,18 +472,18 @@ struct kvaser_usb {
 
 struct kvaser_usb_net_priv {
        struct can_priv can;
-
-       atomic_t active_tx_urbs;
-       struct usb_anchor tx_submitted;
-       struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
-
-       struct completion start_comp, stop_comp;
+       struct can_berr_counter bec;
 
        struct kvaser_usb *dev;
        struct net_device *netdev;
        int channel;
 
-       struct can_berr_counter bec;
+       struct completion start_comp, stop_comp;
+       struct usb_anchor tx_submitted;
+
+       spinlock_t tx_contexts_lock;
+       int active_tx_contexts;
+       struct kvaser_usb_tx_urb_context tx_contexts[];
 };
 
 static const struct usb_device_id kvaser_usb_table[] = {
@@ -590,8 +596,8 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
                         * for further details.
                         */
                        if (tmp->len == 0) {
-                               pos = round_up(pos,
-                                              dev->bulk_in->wMaxPacketSize);
+                               pos = round_up(pos, le16_to_cpu(dev->bulk_in->
+                                                               wMaxPacketSize));
                                continue;
                        }
 
@@ -655,9 +661,13 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
        switch (dev->family) {
        case KVASER_LEAF:
                dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
+               dev->max_tx_urbs =
+                       le16_to_cpu(msg.u.leaf.softinfo.max_outstanding_tx);
                break;
        case KVASER_USBCAN:
                dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
+               dev->max_tx_urbs =
+                       le16_to_cpu(msg.u.usbcan.softinfo.max_outstanding_tx);
                break;
        }
 
@@ -694,6 +704,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
        struct kvaser_usb_net_priv *priv;
        struct sk_buff *skb;
        struct can_frame *cf;
+       unsigned long flags;
        u8 channel, tid;
 
        channel = msg->u.tx_acknowledge_header.channel;
@@ -712,7 +723,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 
        stats = &priv->netdev->stats;
 
-       context = &priv->tx_contexts[tid % MAX_TX_URBS];
+       context = &priv->tx_contexts[tid % dev->max_tx_urbs];
 
        /* Sometimes the state change doesn't come after a bus-off event */
        if (priv->can.restart_ms &&
@@ -737,12 +748,15 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 
        stats->tx_packets++;
        stats->tx_bytes += context->dlc;
-       can_get_echo_skb(priv->netdev, context->echo_index);
 
-       context->echo_index = MAX_TX_URBS;
-       atomic_dec(&priv->active_tx_urbs);
+       spin_lock_irqsave(&priv->tx_contexts_lock, flags);
 
+       can_get_echo_skb(priv->netdev, context->echo_index);
+       context->echo_index = dev->max_tx_urbs;
+       --priv->active_tx_contexts;
        netif_wake_queue(priv->netdev);
+
+       spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
 }
 
 static void kvaser_usb_simple_msg_callback(struct urb *urb)
@@ -803,17 +817,6 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
        return 0;
 }
 
-static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
-{
-       int i;
-
-       usb_kill_anchored_urbs(&priv->tx_submitted);
-       atomic_set(&priv->active_tx_urbs, 0);
-
-       for (i = 0; i < MAX_TX_URBS; i++)
-               priv->tx_contexts[i].echo_index = MAX_TX_URBS;
-}
-
 static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
                                                 const struct kvaser_usb_error_summary *es,
                                                 struct can_frame *cf)
@@ -1334,7 +1337,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
                 * number of events in case of a heavy rx load on the bus.
                 */
                if (msg->len == 0) {
-                       pos = round_up(pos, dev->bulk_in->wMaxPacketSize);
+                       pos = round_up(pos, le16_to_cpu(dev->bulk_in->
+                                                       wMaxPacketSize));
                        continue;
                }
 
@@ -1515,6 +1519,26 @@ error:
        return err;
 }
 
+static void kvaser_usb_reset_tx_urb_contexts(struct kvaser_usb_net_priv *priv)
+{
+       int i, max_tx_urbs;
+
+       max_tx_urbs = priv->dev->max_tx_urbs;
+
+       priv->active_tx_contexts = 0;
+       for (i = 0; i < max_tx_urbs; i++)
+               priv->tx_contexts[i].echo_index = max_tx_urbs;
+}
+
+/* This method might sleep. Do not call it in the atomic context
+ * of URB completions.
+ */
+static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
+{
+       usb_kill_anchored_urbs(&priv->tx_submitted);
+       kvaser_usb_reset_tx_urb_contexts(priv);
+}
+
 static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
 {
        int i;
@@ -1634,6 +1658,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        struct kvaser_msg *msg;
        int i, err, ret = NETDEV_TX_OK;
        u8 *msg_tx_can_flags = NULL;            /* GCC */
+       unsigned long flags;
 
        if (can_dropped_invalid_skb(netdev, skb))
                return NETDEV_TX_OK;
@@ -1687,12 +1712,21 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        if (cf->can_id & CAN_RTR_FLAG)
                *msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
 
-       for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
-               if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+       spin_lock_irqsave(&priv->tx_contexts_lock, flags);
+       for (i = 0; i < dev->max_tx_urbs; i++) {
+               if (priv->tx_contexts[i].echo_index == dev->max_tx_urbs) {
                        context = &priv->tx_contexts[i];
+
+                       context->echo_index = i;
+                       can_put_echo_skb(skb, netdev, context->echo_index);
+                       ++priv->active_tx_contexts;
+                       if (priv->active_tx_contexts >= dev->max_tx_urbs)
+                               netif_stop_queue(netdev);
+
                        break;
                }
        }
+       spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
 
        /* This should never happen; it implies a flow control bug */
        if (!context) {
@@ -1704,7 +1738,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        }
 
        context->priv = priv;
-       context->echo_index = i;
        context->dlc = cf->can_dlc;
 
        msg->u.tx_can.tid = context->echo_index;
@@ -1716,18 +1749,17 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                          kvaser_usb_write_bulk_callback, context);
        usb_anchor_urb(urb, &priv->tx_submitted);
 
-       can_put_echo_skb(skb, netdev, context->echo_index);
-
-       atomic_inc(&priv->active_tx_urbs);
-
-       if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
-               netif_stop_queue(netdev);
-
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (unlikely(err)) {
+               spin_lock_irqsave(&priv->tx_contexts_lock, flags);
+
                can_free_echo_skb(netdev, context->echo_index);
+               context->echo_index = dev->max_tx_urbs;
+               --priv->active_tx_contexts;
+               netif_wake_queue(netdev);
+
+               spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
 
-               atomic_dec(&priv->active_tx_urbs);
                usb_unanchor_urb(urb);
 
                stats->tx_dropped++;
@@ -1854,13 +1886,15 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
        struct kvaser_usb *dev = usb_get_intfdata(intf);
        struct net_device *netdev;
        struct kvaser_usb_net_priv *priv;
-       int i, err;
+       int err;
 
        err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, channel);
        if (err)
                return err;
 
-       netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
+       netdev = alloc_candev(sizeof(*priv) +
+                             dev->max_tx_urbs * sizeof(*priv->tx_contexts),
+                             dev->max_tx_urbs);
        if (!netdev) {
                dev_err(&intf->dev, "Cannot alloc candev\n");
                return -ENOMEM;
@@ -1868,19 +1902,17 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
 
        priv = netdev_priv(netdev);
 
+       init_usb_anchor(&priv->tx_submitted);
        init_completion(&priv->start_comp);
        init_completion(&priv->stop_comp);
 
-       init_usb_anchor(&priv->tx_submitted);
-       atomic_set(&priv->active_tx_urbs, 0);
-
-       for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++)
-               priv->tx_contexts[i].echo_index = MAX_TX_URBS;
-
        priv->dev = dev;
        priv->netdev = netdev;
        priv->channel = channel;
 
+       spin_lock_init(&priv->tx_contexts_lock);
+       kvaser_usb_reset_tx_urb_contexts(priv);
+
        priv->can.state = CAN_STATE_STOPPED;
        priv->can.clock.freq = CAN_USB_CLOCK;
        priv->can.bittiming_const = &kvaser_usb_bittiming_const;
@@ -1990,6 +2022,13 @@ static int kvaser_usb_probe(struct usb_interface *intf,
                return err;
        }
 
+       dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
+               ((dev->fw_version >> 24) & 0xff),
+               ((dev->fw_version >> 16) & 0xff),
+               (dev->fw_version & 0xffff));
+
+       dev_dbg(&intf->dev, "Max oustanding tx = %d URBs\n", dev->max_tx_urbs);
+
        err = kvaser_usb_get_card_info(dev);
        if (err) {
                dev_err(&intf->dev,
@@ -1997,11 +2036,6 @@ static int kvaser_usb_probe(struct usb_interface *intf,
                return err;
        }
 
-       dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
-               ((dev->fw_version >> 24) & 0xff),
-               ((dev->fw_version >> 16) & 0xff),
-               (dev->fw_version & 0xffff));
-
        for (i = 0; i < dev->nchannels; i++) {
                err = kvaser_usb_init_one(intf, id, i);
                if (err) {
index 1ba7c25..e8fc495 100644 (file)
@@ -26,8 +26,8 @@
 #define PUCAN_CMD_FILTER_STD           0x008
 #define PUCAN_CMD_TX_ABORT             0x009
 #define PUCAN_CMD_WR_ERR_CNT           0x00a
-#define PUCAN_CMD_RX_FRAME_ENABLE      0x00b
-#define PUCAN_CMD_RX_FRAME_DISABLE     0x00c
+#define PUCAN_CMD_SET_EN_OPTION                0x00b
+#define PUCAN_CMD_CLR_DIS_OPTION       0x00c
 #define PUCAN_CMD_END_OF_COLLECTION    0x3ff
 
 /* uCAN received messages list */
@@ -101,14 +101,15 @@ struct __packed pucan_wr_err_cnt {
        u16     unused;
 };
 
-/* uCAN RX_FRAME_ENABLE command fields */
-#define PUCAN_FLTEXT_ERROR             0x0001
-#define PUCAN_FLTEXT_BUSLOAD           0x0002
+/* uCAN SET_EN/CLR_DIS _OPTION command fields */
+#define PUCAN_OPTION_ERROR             0x0001
+#define PUCAN_OPTION_BUSLOAD           0x0002
+#define PUCAN_OPTION_CANDFDISO         0x0004
 
-struct __packed pucan_filter_ext {
+struct __packed pucan_options {
        __le16  opcode_channel;
 
-       __le16  ext_mask;
+       __le16  options;
        u32     unused;
 };
 
index 0bac0f1..a9221ad 100644 (file)
@@ -110,13 +110,13 @@ struct __packed pcan_ufd_led {
        u8      unused[5];
 };
 
-/* Extended usage of uCAN commands CMD_RX_FRAME_xxxABLE for PCAN-USB Pro FD */
+/* Extended usage of uCAN commands CMD_xxx_xx_OPTION for PCAN-USB Pro FD */
 #define PCAN_UFD_FLTEXT_CALIBRATION    0x8000
 
-struct __packed pcan_ufd_filter_ext {
+struct __packed pcan_ufd_options {
        __le16  opcode_channel;
 
-       __le16  ext_mask;
+       __le16  ucan_mask;
        u16     unused;
        __le16  usb_mask;
 };
@@ -251,6 +251,27 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf)
        /* moves the pointer forward */
        pc += sizeof(struct pucan_wr_err_cnt);
 
+       /* add command to switch from ISO to non-ISO mode, if fw allows it */
+       if (dev->can.ctrlmode_supported & CAN_CTRLMODE_FD_NON_ISO) {
+               struct pucan_options *puo = (struct pucan_options *)pc;
+
+               puo->opcode_channel =
+                       (dev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) ?
+                       pucan_cmd_opcode_channel(dev,
+                                                PUCAN_CMD_CLR_DIS_OPTION) :
+                       pucan_cmd_opcode_channel(dev, PUCAN_CMD_SET_EN_OPTION);
+
+               puo->options = cpu_to_le16(PUCAN_OPTION_CANDFDISO);
+
+               /* to be sure that no other extended bits will be taken into
+                * account
+                */
+               puo->unused = 0;
+
+               /* moves the pointer forward */
+               pc += sizeof(struct pucan_options);
+       }
+
        /* next, go back to operational mode */
        cmd = (struct pucan_command *)pc;
        cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
@@ -321,21 +342,21 @@ static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx,
        return pcan_usb_fd_send_cmd(dev, cmd);
 }
 
-/* set/unset notifications filter:
+/* set/unset options
  *
- *     onoff   sets(1)/unset(0) notifications
- *     mask    each bit defines a kind of notification to set/unset
+ *     onoff   set(1)/unset(0) options
+ *     mask    each bit defines a kind of options to set/unset
  */
-static int pcan_usb_fd_set_filter_ext(struct peak_usb_device *dev,
-                                     bool onoff, u16 ext_mask, u16 usb_mask)
+static int pcan_usb_fd_set_options(struct peak_usb_device *dev,
+                                  bool onoff, u16 ucan_mask, u16 usb_mask)
 {
-       struct pcan_ufd_filter_ext *cmd = pcan_usb_fd_cmd_buffer(dev);
+       struct pcan_ufd_options *cmd = pcan_usb_fd_cmd_buffer(dev);
 
        cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
-                                       (onoff) ? PUCAN_CMD_RX_FRAME_ENABLE :
-                                                 PUCAN_CMD_RX_FRAME_DISABLE);
+                                       (onoff) ? PUCAN_CMD_SET_EN_OPTION :
+                                                 PUCAN_CMD_CLR_DIS_OPTION);
 
-       cmd->ext_mask = cpu_to_le16(ext_mask);
+       cmd->ucan_mask = cpu_to_le16(ucan_mask);
        cmd->usb_mask = cpu_to_le16(usb_mask);
 
        /* send the command */
@@ -770,9 +791,9 @@ static int pcan_usb_fd_start(struct peak_usb_device *dev)
                                       &pcan_usb_pro_fd);
 
                /* enable USB calibration messages */
-               err = pcan_usb_fd_set_filter_ext(dev, 1,
-                                                PUCAN_FLTEXT_ERROR,
-                                                PCAN_UFD_FLTEXT_CALIBRATION);
+               err = pcan_usb_fd_set_options(dev, 1,
+                                             PUCAN_OPTION_ERROR,
+                                             PCAN_UFD_FLTEXT_CALIBRATION);
        }
 
        pdev->usb_if->dev_opened_count++;
@@ -806,9 +827,9 @@ static int pcan_usb_fd_stop(struct peak_usb_device *dev)
 
        /* turn off special msgs for that interface if no other dev opened */
        if (pdev->usb_if->dev_opened_count == 1)
-               pcan_usb_fd_set_filter_ext(dev, 0,
-                                          PUCAN_FLTEXT_ERROR,
-                                          PCAN_UFD_FLTEXT_CALIBRATION);
+               pcan_usb_fd_set_options(dev, 0,
+                                       PUCAN_OPTION_ERROR,
+                                       PCAN_UFD_FLTEXT_CALIBRATION);
        pdev->usb_if->dev_opened_count--;
 
        return 0;
@@ -860,8 +881,14 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
                         pdev->usb_if->fw_info.fw_version[2],
                         dev->adapter->ctrl_count);
 
-               /* the currently supported hw is non-ISO */
-               dev->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO;
+               /* check for ability to switch between ISO/non-ISO modes */
+               if (pdev->usb_if->fw_info.fw_version[0] >= 2) {
+                       /* firmware >= 2.x supports ISO/non-ISO switching */
+                       dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO;
+               } else {
+                       /* firmware < 2.x only supports fixed(!) non-ISO */
+                       dev->can.ctrlmode |= CAN_CTRLMODE_FD_NON_ISO;
+               }
 
                /* tell the hardware the can driver is running */
                err = pcan_usb_fd_drv_loaded(dev, 1);
@@ -937,9 +964,9 @@ static void pcan_usb_fd_exit(struct peak_usb_device *dev)
        if (dev->ctrl_idx == 0) {
                /* turn off calibration message if any device were opened */
                if (pdev->usb_if->dev_opened_count > 0)
-                       pcan_usb_fd_set_filter_ext(dev, 0,
-                                                  PUCAN_FLTEXT_ERROR,
-                                                  PCAN_UFD_FLTEXT_CALIBRATION);
+                       pcan_usb_fd_set_options(dev, 0,
+                                               PUCAN_OPTION_ERROR,
+                                               PCAN_UFD_FLTEXT_CALIBRATION);
 
                /* tell USB adapter that the driver is being unloaded */
                pcan_usb_fd_drv_loaded(dev, 0);
index 11d6e65..15a8190 100644 (file)
@@ -1543,7 +1543,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
 {
        struct pcnet32_private *lp;
        int i, media;
-       int fdx, mii, fset, dxsuflo;
+       int fdx, mii, fset, dxsuflo, sram;
        int chip_version;
        char *chipname;
        struct net_device *dev;
@@ -1580,7 +1580,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
        }
 
        /* initialize variables */
-       fdx = mii = fset = dxsuflo = 0;
+       fdx = mii = fset = dxsuflo = sram = 0;
        chip_version = (chip_version >> 12) & 0xffff;
 
        switch (chip_version) {
@@ -1613,6 +1613,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                chipname = "PCnet/FAST III 79C973";     /* PCI */
                fdx = 1;
                mii = 1;
+               sram = 1;
                break;
        case 0x2626:
                chipname = "PCnet/Home 79C978"; /* PCI */
@@ -1636,6 +1637,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                chipname = "PCnet/FAST III 79C975";     /* PCI */
                fdx = 1;
                mii = 1;
+               sram = 1;
                break;
        case 0x2628:
                chipname = "PCnet/PRO 79C976";
@@ -1664,6 +1666,31 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                dxsuflo = 1;
        }
 
+       /*
+        * The Am79C973/Am79C975 controllers come with 12K of SRAM
+        * which we can use for the Tx/Rx buffers but most importantly,
+        * the use of SRAM allow us to use the BCR18:NOUFLO bit to avoid
+        * Tx fifo underflows.
+        */
+       if (sram) {
+               /*
+                * The SRAM is being configured in two steps. First we
+                * set the SRAM size in the BCR25:SRAM_SIZE bits. According
+                * to the datasheet, each bit corresponds to a 512-byte
+                * page so we can have at most 24 pages. The SRAM_SIZE
+                * holds the value of the upper 8 bits of the 16-bit SRAM size.
+                * The low 8-bits start at 0x00 and end at 0xff. So the
+                * address range is from 0x0000 up to 0x17ff. Therefore,
+                * the SRAM_SIZE is set to 0x17. The next step is to set
+                * the BCR26:SRAM_BND midway through so the Tx and Rx
+                * buffers can share the SRAM equally.
+                */
+               a->write_bcr(ioaddr, 25, 0x17);
+               a->write_bcr(ioaddr, 26, 0xc);
+               /* And finally enable the NOUFLO bit */
+               a->write_bcr(ioaddr, 18, a->read_bcr(ioaddr, 18) | (1 << 11));
+       }
+
        dev = alloc_etherdev(sizeof(*lp));
        if (!dev) {
                ret = -ENOMEM;
index 756053c..4085c4b 100644 (file)
@@ -1811,7 +1811,7 @@ struct bnx2x {
        int                     stats_state;
 
        /* used for synchronization of concurrent threads statistics handling */
-       spinlock_t              stats_lock;
+       struct mutex            stats_lock;
 
        /* used by dmae command loader */
        struct dmae_command     stats_dmae;
@@ -1935,8 +1935,6 @@ struct bnx2x {
 
        int fp_array_size;
        u32 dump_preset_idx;
-       bool                                    stats_started;
-       struct semaphore                        stats_sema;
 
        u8                                      phys_port_id[ETH_ALEN];
 
index bef750a..1ec635f 100644 (file)
@@ -129,8 +129,8 @@ struct bnx2x_mac_vals {
        u32 xmac_val;
        u32 emac_addr;
        u32 emac_val;
-       u32 umac_addr;
-       u32 umac_val;
+       u32 umac_addr[2];
+       u32 umac_val[2];
        u32 bmac_addr;
        u32 bmac_val[2];
 };
@@ -7866,6 +7866,20 @@ int bnx2x_init_hw_func_cnic(struct bnx2x *bp)
        return 0;
 }
 
+/* previous driver DMAE transaction may have occurred when pre-boot stage ended
+ * and boot began, or when kdump kernel was loaded. Either case would invalidate
+ * the addresses of the transaction, resulting in was-error bit set in the pci
+ * causing all hw-to-host pcie transactions to timeout. If this happened we want
+ * to clear the interrupt which detected this from the pglueb and the was done
+ * bit
+ */
+static void bnx2x_clean_pglue_errors(struct bnx2x *bp)
+{
+       if (!CHIP_IS_E1x(bp))
+               REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR,
+                      1 << BP_ABS_FUNC(bp));
+}
+
 static int bnx2x_init_hw_func(struct bnx2x *bp)
 {
        int port = BP_PORT(bp);
@@ -7958,8 +7972,7 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
 
        bnx2x_init_block(bp, BLOCK_PGLUE_B, init_phase);
 
-       if (!CHIP_IS_E1x(bp))
-               REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, func);
+       bnx2x_clean_pglue_errors(bp);
 
        bnx2x_init_block(bp, BLOCK_ATC, init_phase);
        bnx2x_init_block(bp, BLOCK_DMAE, init_phase);
@@ -10141,6 +10154,25 @@ static u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
        return base + (BP_ABS_FUNC(bp)) * stride;
 }
 
+static bool bnx2x_prev_unload_close_umac(struct bnx2x *bp,
+                                        u8 port, u32 reset_reg,
+                                        struct bnx2x_mac_vals *vals)
+{
+       u32 mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port;
+       u32 base_addr;
+
+       if (!(mask & reset_reg))
+               return false;
+
+       BNX2X_DEV_INFO("Disable umac Rx %02x\n", port);
+       base_addr = port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
+       vals->umac_addr[port] = base_addr + UMAC_REG_COMMAND_CONFIG;
+       vals->umac_val[port] = REG_RD(bp, vals->umac_addr[port]);
+       REG_WR(bp, vals->umac_addr[port], 0);
+
+       return true;
+}
+
 static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
                                        struct bnx2x_mac_vals *vals)
 {
@@ -10149,10 +10181,7 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
        u8 port = BP_PORT(bp);
 
        /* reset addresses as they also mark which values were changed */
-       vals->bmac_addr = 0;
-       vals->umac_addr = 0;
-       vals->xmac_addr = 0;
-       vals->emac_addr = 0;
+       memset(vals, 0, sizeof(*vals));
 
        reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2);
 
@@ -10201,15 +10230,11 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
                        REG_WR(bp, vals->xmac_addr, 0);
                        mac_stopped = true;
                }
-               mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port;
-               if (mask & reset_reg) {
-                       BNX2X_DEV_INFO("Disable umac Rx\n");
-                       base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
-                       vals->umac_addr = base_addr + UMAC_REG_COMMAND_CONFIG;
-                       vals->umac_val = REG_RD(bp, vals->umac_addr);
-                       REG_WR(bp, vals->umac_addr, 0);
-                       mac_stopped = true;
-               }
+
+               mac_stopped |= bnx2x_prev_unload_close_umac(bp, 0,
+                                                           reset_reg, vals);
+               mac_stopped |= bnx2x_prev_unload_close_umac(bp, 1,
+                                                           reset_reg, vals);
        }
 
        if (mac_stopped)
@@ -10505,8 +10530,11 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                /* Close the MAC Rx to prevent BRB from filling up */
                bnx2x_prev_unload_close_mac(bp, &mac_vals);
 
-               /* close LLH filters towards the BRB */
+               /* close LLH filters for both ports towards the BRB */
                bnx2x_set_rx_filter(&bp->link_params, 0);
+               bp->link_params.port ^= 1;
+               bnx2x_set_rx_filter(&bp->link_params, 0);
+               bp->link_params.port ^= 1;
 
                /* Check if the UNDI driver was previously loaded */
                if (bnx2x_prev_is_after_undi(bp)) {
@@ -10553,8 +10581,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
 
        if (mac_vals.xmac_addr)
                REG_WR(bp, mac_vals.xmac_addr, mac_vals.xmac_val);
-       if (mac_vals.umac_addr)
-               REG_WR(bp, mac_vals.umac_addr, mac_vals.umac_val);
+       if (mac_vals.umac_addr[0])
+               REG_WR(bp, mac_vals.umac_addr[0], mac_vals.umac_val[0]);
+       if (mac_vals.umac_addr[1])
+               REG_WR(bp, mac_vals.umac_addr[1], mac_vals.umac_val[1]);
        if (mac_vals.emac_addr)
                REG_WR(bp, mac_vals.emac_addr, mac_vals.emac_val);
        if (mac_vals.bmac_addr) {
@@ -10571,26 +10601,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
        return bnx2x_prev_mcp_done(bp);
 }
 
-/* previous driver DMAE transaction may have occurred when pre-boot stage ended
- * and boot began, or when kdump kernel was loaded. Either case would invalidate
- * the addresses of the transaction, resulting in was-error bit set in the pci
- * causing all hw-to-host pcie transactions to timeout. If this happened we want
- * to clear the interrupt which detected this from the pglueb and the was done
- * bit
- */
-static void bnx2x_prev_interrupted_dmae(struct bnx2x *bp)
-{
-       if (!CHIP_IS_E1x(bp)) {
-               u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS);
-               if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) {
-                       DP(BNX2X_MSG_SP,
-                          "'was error' bit was found to be set in pglueb upon startup. Clearing\n");
-                       REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR,
-                              1 << BP_FUNC(bp));
-               }
-       }
-}
-
 static int bnx2x_prev_unload(struct bnx2x *bp)
 {
        int time_counter = 10;
@@ -10600,7 +10610,7 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
        /* clear hw from errors which may have resulted from an interrupted
         * dmae transaction.
         */
-       bnx2x_prev_interrupted_dmae(bp);
+       bnx2x_clean_pglue_errors(bp);
 
        /* Release previously held locks */
        hw_lock_reg = (BP_FUNC(bp) <= 5) ?
@@ -12037,9 +12047,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        mutex_init(&bp->port.phy_mutex);
        mutex_init(&bp->fw_mb_mutex);
        mutex_init(&bp->drv_info_mutex);
+       mutex_init(&bp->stats_lock);
        bp->drv_info_mng_owner = false;
-       spin_lock_init(&bp->stats_lock);
-       sema_init(&bp->stats_sema, 1);
 
        INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
        INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
@@ -12769,7 +12778,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
                NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 |
                NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_GRO |
                NETIF_F_RXHASH | NETIF_F_HW_VLAN_CTAG_TX;
-       if (!CHIP_IS_E1x(bp)) {
+       if (!chip_is_e1x) {
                dev->hw_features |= NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL |
                                    NETIF_F_GSO_IPIP | NETIF_F_GSO_SIT;
                dev->hw_enc_features =
@@ -13668,9 +13677,9 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
        cancel_delayed_work_sync(&bp->sp_task);
        cancel_delayed_work_sync(&bp->period_task);
 
-       spin_lock_bh(&bp->stats_lock);
+       mutex_lock(&bp->stats_lock);
        bp->stats_state = STATS_STATE_DISABLED;
-       spin_unlock_bh(&bp->stats_lock);
+       mutex_unlock(&bp->stats_lock);
 
        bnx2x_save_statistics(bp);
 
index e5aca2d..cfe3c76 100644 (file)
@@ -2238,7 +2238,9 @@ int bnx2x_vf_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
 
                cookie.vf = vf;
                cookie.state = VF_ACQUIRED;
-               bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie);
+               rc = bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie);
+               if (rc)
+                       goto op_err;
        }
 
        DP(BNX2X_MSG_IOV, "set state to acquired\n");
index d160829..800ab44 100644 (file)
@@ -123,36 +123,28 @@ static void bnx2x_dp_stats(struct bnx2x *bp)
  */
 static void bnx2x_storm_stats_post(struct bnx2x *bp)
 {
-       if (!bp->stats_pending) {
-               int rc;
+       int rc;
 
-               spin_lock_bh(&bp->stats_lock);
-
-               if (bp->stats_pending) {
-                       spin_unlock_bh(&bp->stats_lock);
-                       return;
-               }
-
-               bp->fw_stats_req->hdr.drv_stats_counter =
-                       cpu_to_le16(bp->stats_counter++);
+       if (bp->stats_pending)
+               return;
 
-               DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
-                  le16_to_cpu(bp->fw_stats_req->hdr.drv_stats_counter));
+       bp->fw_stats_req->hdr.drv_stats_counter =
+               cpu_to_le16(bp->stats_counter++);
 
-               /* adjust the ramrod to include VF queues statistics */
-               bnx2x_iov_adjust_stats_req(bp);
-               bnx2x_dp_stats(bp);
+       DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
+          le16_to_cpu(bp->fw_stats_req->hdr.drv_stats_counter));
 
-               /* send FW stats ramrod */
-               rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
-                                  U64_HI(bp->fw_stats_req_mapping),
-                                  U64_LO(bp->fw_stats_req_mapping),
-                                  NONE_CONNECTION_TYPE);
-               if (rc == 0)
-                       bp->stats_pending = 1;
+       /* adjust the ramrod to include VF queues statistics */
+       bnx2x_iov_adjust_stats_req(bp);
+       bnx2x_dp_stats(bp);
 
-               spin_unlock_bh(&bp->stats_lock);
-       }
+       /* send FW stats ramrod */
+       rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
+                          U64_HI(bp->fw_stats_req_mapping),
+                          U64_LO(bp->fw_stats_req_mapping),
+                          NONE_CONNECTION_TYPE);
+       if (rc == 0)
+               bp->stats_pending = 1;
 }
 
 static void bnx2x_hw_stats_post(struct bnx2x *bp)
@@ -221,7 +213,7 @@ static void bnx2x_stats_comp(struct bnx2x *bp)
  */
 
 /* should be called under stats_sema */
-static void __bnx2x_stats_pmf_update(struct bnx2x *bp)
+static void bnx2x_stats_pmf_update(struct bnx2x *bp)
 {
        struct dmae_command *dmae;
        u32 opcode;
@@ -519,7 +511,7 @@ static void bnx2x_func_stats_init(struct bnx2x *bp)
 }
 
 /* should be called under stats_sema */
-static void __bnx2x_stats_start(struct bnx2x *bp)
+static void bnx2x_stats_start(struct bnx2x *bp)
 {
        if (IS_PF(bp)) {
                if (bp->port.pmf)
@@ -531,34 +523,13 @@ static void __bnx2x_stats_start(struct bnx2x *bp)
                bnx2x_hw_stats_post(bp);
                bnx2x_storm_stats_post(bp);
        }
-
-       bp->stats_started = true;
-}
-
-static void bnx2x_stats_start(struct bnx2x *bp)
-{
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
 }
 
 static void bnx2x_stats_pmf_start(struct bnx2x *bp)
 {
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
        bnx2x_stats_comp(bp);
-       __bnx2x_stats_pmf_update(bp);
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
-}
-
-static void bnx2x_stats_pmf_update(struct bnx2x *bp)
-{
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
-       __bnx2x_stats_pmf_update(bp);
-       up(&bp->stats_sema);
+       bnx2x_stats_pmf_update(bp);
+       bnx2x_stats_start(bp);
 }
 
 static void bnx2x_stats_restart(struct bnx2x *bp)
@@ -568,11 +539,9 @@ static void bnx2x_stats_restart(struct bnx2x *bp)
         */
        if (IS_VF(bp))
                return;
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
+
        bnx2x_stats_comp(bp);
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
+       bnx2x_stats_start(bp);
 }
 
 static void bnx2x_bmac_stats_update(struct bnx2x *bp)
@@ -1246,18 +1215,12 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 {
        u32 *stats_comp = bnx2x_sp(bp, stats_comp);
 
-       /* we run update from timer context, so give up
-        * if somebody is in the middle of transition
-        */
-       if (down_trylock(&bp->stats_sema))
+       if (bnx2x_edebug_stats_stopped(bp))
                return;
 
-       if (bnx2x_edebug_stats_stopped(bp) || !bp->stats_started)
-               goto out;
-
        if (IS_PF(bp)) {
                if (*stats_comp != DMAE_COMP_VAL)
-                       goto out;
+                       return;
 
                if (bp->port.pmf)
                        bnx2x_hw_stats_update(bp);
@@ -1267,7 +1230,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
                                BNX2X_ERR("storm stats were not updated for 3 times\n");
                                bnx2x_panic();
                        }
-                       goto out;
+                       return;
                }
        } else {
                /* vf doesn't collect HW statistics, and doesn't get completions
@@ -1281,7 +1244,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 
        /* vf is done */
        if (IS_VF(bp))
-               goto out;
+               return;
 
        if (netif_msg_timer(bp)) {
                struct bnx2x_eth_stats *estats = &bp->eth_stats;
@@ -1292,9 +1255,6 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 
        bnx2x_hw_stats_post(bp);
        bnx2x_storm_stats_post(bp);
-
-out:
-       up(&bp->stats_sema);
 }
 
 static void bnx2x_port_stats_stop(struct bnx2x *bp)
@@ -1358,12 +1318,7 @@ static void bnx2x_port_stats_stop(struct bnx2x *bp)
 
 static void bnx2x_stats_stop(struct bnx2x *bp)
 {
-       int update = 0;
-
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
-
-       bp->stats_started = false;
+       bool update = false;
 
        bnx2x_stats_comp(bp);
 
@@ -1381,8 +1336,6 @@ static void bnx2x_stats_stop(struct bnx2x *bp)
                bnx2x_hw_stats_post(bp);
                bnx2x_stats_comp(bp);
        }
-
-       up(&bp->stats_sema);
 }
 
 static void bnx2x_stats_do_nothing(struct bnx2x *bp)
@@ -1410,18 +1363,28 @@ static const struct {
 
 void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
 {
-       enum bnx2x_stats_state state;
-       void (*action)(struct bnx2x *bp);
+       enum bnx2x_stats_state state = bp->stats_state;
+
        if (unlikely(bp->panic))
                return;
 
-       spin_lock_bh(&bp->stats_lock);
-       state = bp->stats_state;
+       /* Statistics update run from timer context, and we don't want to stop
+        * that context in case someone is in the middle of a transition.
+        * For other events, wait a bit until lock is taken.
+        */
+       if (!mutex_trylock(&bp->stats_lock)) {
+               if (event == STATS_EVENT_UPDATE)
+                       return;
+
+               DP(BNX2X_MSG_STATS,
+                  "Unlikely stats' lock contention [event %d]\n", event);
+               mutex_lock(&bp->stats_lock);
+       }
+
+       bnx2x_stats_stm[state][event].action(bp);
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
-       action = bnx2x_stats_stm[state][event].action;
-       spin_unlock_bh(&bp->stats_lock);
 
-       action(bp);
+       mutex_unlock(&bp->stats_lock);
 
        if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
@@ -1998,13 +1961,34 @@ void bnx2x_afex_collect_stats(struct bnx2x *bp, void *void_afex_stats,
        }
 }
 
-void bnx2x_stats_safe_exec(struct bnx2x *bp,
-                          void (func_to_exec)(void *cookie),
-                          void *cookie){
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
+int bnx2x_stats_safe_exec(struct bnx2x *bp,
+                         void (func_to_exec)(void *cookie),
+                         void *cookie)
+{
+       int cnt = 10, rc = 0;
+
+       /* Wait for statistics to end [while blocking further requests],
+        * then run supplied function 'safely'.
+        */
+       mutex_lock(&bp->stats_lock);
+
        bnx2x_stats_comp(bp);
+       while (bp->stats_pending && cnt--)
+               if (bnx2x_storm_stats_update(bp))
+                       usleep_range(1000, 2000);
+       if (bp->stats_pending) {
+               BNX2X_ERR("Failed to wait for stats pending to clear [possibly FW is stuck]\n");
+               rc = -EBUSY;
+               goto out;
+       }
+
        func_to_exec(cookie);
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
+
+out:
+       /* No need to restart statistics - if they're enabled, the timer
+        * will restart the statistics.
+        */
+       mutex_unlock(&bp->stats_lock);
+
+       return rc;
 }
index 2beceae..965539a 100644 (file)
@@ -539,9 +539,9 @@ struct bnx2x;
 void bnx2x_memset_stats(struct bnx2x *bp);
 void bnx2x_stats_init(struct bnx2x *bp);
 void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
-void bnx2x_stats_safe_exec(struct bnx2x *bp,
-                          void (func_to_exec)(void *cookie),
-                          void *cookie);
+int bnx2x_stats_safe_exec(struct bnx2x *bp,
+                         void (func_to_exec)(void *cookie),
+                         void *cookie);
 
 /**
  * bnx2x_save_statistics - save statistics when unloading.
index 97842d0..c6ff489 100644 (file)
@@ -376,8 +376,6 @@ enum {
 enum {
        INGQ_EXTRAS = 2,        /* firmware event queue and */
                                /*   forwarded interrupts */
-       MAX_EGRQ = MAX_ETH_QSETS*2 + MAX_OFLD_QSETS*2
-                  + MAX_CTRL_QUEUES + MAX_RDMA_QUEUES + MAX_ISCSI_QUEUES,
        MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES
                   + MAX_RDMA_CIQS + MAX_ISCSI_QUEUES + INGQ_EXTRAS,
 };
@@ -616,11 +614,13 @@ struct sge {
        unsigned int idma_qid[2];   /* SGE IDMA Hung Ingress Queue ID */
 
        unsigned int egr_start;
+       unsigned int egr_sz;
        unsigned int ingr_start;
-       void *egr_map[MAX_EGRQ];    /* qid->queue egress queue map */
-       struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */
-       DECLARE_BITMAP(starving_fl, MAX_EGRQ);
-       DECLARE_BITMAP(txq_maperr, MAX_EGRQ);
+       unsigned int ingr_sz;
+       void **egr_map;    /* qid->queue egress queue map */
+       struct sge_rspq **ingr_map; /* qid->queue ingress queue map */
+       unsigned long *starving_fl;
+       unsigned long *txq_maperr;
        struct timer_list rx_timer; /* refills starving FLs */
        struct timer_list tx_timer; /* checks Tx queues */
 };
@@ -1136,6 +1136,8 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
 
 unsigned int qtimer_val(const struct adapter *adap,
                        const struct sge_rspq *q);
+
+int t4_init_devlog_params(struct adapter *adapter);
 int t4_init_sge_params(struct adapter *adapter);
 int t4_init_tp_params(struct adapter *adap);
 int t4_filter_field_shift(const struct adapter *adap, int filter_sel);
index 78854ce..dcb0479 100644 (file)
@@ -670,9 +670,13 @@ static int cctrl_tbl_show(struct seq_file *seq, void *v)
                "0.9375" };
 
        int i;
-       u16 incr[NMTUS][NCCTRL_WIN];
+       u16 (*incr)[NCCTRL_WIN];
        struct adapter *adap = seq->private;
 
+       incr = kmalloc(sizeof(*incr) * NMTUS, GFP_KERNEL);
+       if (!incr)
+               return -ENOMEM;
+
        t4_read_cong_tbl(adap, incr);
 
        for (i = 0; i < NCCTRL_WIN; ++i) {
@@ -685,6 +689,8 @@ static int cctrl_tbl_show(struct seq_file *seq, void *v)
                           adap->params.a_wnd[i],
                           dec_fac[adap->params.b_wnd[i]]);
        }
+
+       kfree(incr);
        return 0;
 }
 
index a22cf93..d929951 100644 (file)
@@ -920,7 +920,7 @@ static void quiesce_rx(struct adapter *adap)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) {
+       for (i = 0; i < adap->sge.ingr_sz; i++) {
                struct sge_rspq *q = adap->sge.ingr_map[i];
 
                if (q && q->handler) {
@@ -934,6 +934,21 @@ static void quiesce_rx(struct adapter *adap)
        }
 }
 
+/* Disable interrupt and napi handler */
+static void disable_interrupts(struct adapter *adap)
+{
+       if (adap->flags & FULL_INIT_DONE) {
+               t4_intr_disable(adap);
+               if (adap->flags & USING_MSIX) {
+                       free_msix_queue_irqs(adap);
+                       free_irq(adap->msix_info[0].vec, adap);
+               } else {
+                       free_irq(adap->pdev->irq, adap);
+               }
+               quiesce_rx(adap);
+       }
+}
+
 /*
  * Enable NAPI scheduling and interrupt generation for all Rx queues.
  */
@@ -941,7 +956,7 @@ static void enable_rx(struct adapter *adap)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) {
+       for (i = 0; i < adap->sge.ingr_sz; i++) {
                struct sge_rspq *q = adap->sge.ingr_map[i];
 
                if (!q)
@@ -970,8 +985,8 @@ static int setup_sge_queues(struct adapter *adap)
        int err, msi_idx, i, j;
        struct sge *s = &adap->sge;
 
-       bitmap_zero(s->starving_fl, MAX_EGRQ);
-       bitmap_zero(s->txq_maperr, MAX_EGRQ);
+       bitmap_zero(s->starving_fl, s->egr_sz);
+       bitmap_zero(s->txq_maperr, s->egr_sz);
 
        if (adap->flags & USING_MSIX)
                msi_idx = 1;         /* vector 0 is for non-queue interrupts */
@@ -983,6 +998,19 @@ static int setup_sge_queues(struct adapter *adap)
                msi_idx = -((int)s->intrq.abs_id + 1);
        }
 
+       /* NOTE: If you add/delete any Ingress/Egress Queue allocations in here,
+        * don't forget to update the following which need to be
+        * synchronized to and changes here.
+        *
+        * 1. The calculations of MAX_INGQ in cxgb4.h.
+        *
+        * 2. Update enable_msix/name_msix_vecs/request_msix_queue_irqs
+        *    to accommodate any new/deleted Ingress Queues
+        *    which need MSI-X Vectors.
+        *
+        * 3. Update sge_qinfo_show() to include information on the
+        *    new/deleted queues.
+        */
        err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0],
                               msi_idx, NULL, fwevtq_handler);
        if (err) {
@@ -4244,19 +4272,12 @@ static int cxgb_up(struct adapter *adap)
 
 static void cxgb_down(struct adapter *adapter)
 {
-       t4_intr_disable(adapter);
        cancel_work_sync(&adapter->tid_release_task);
        cancel_work_sync(&adapter->db_full_task);
        cancel_work_sync(&adapter->db_drop_task);
        adapter->tid_release_task_busy = false;
        adapter->tid_release_head = NULL;
 
-       if (adapter->flags & USING_MSIX) {
-               free_msix_queue_irqs(adapter);
-               free_irq(adapter->msix_info[0].vec, adapter);
-       } else
-               free_irq(adapter->pdev->irq, adapter);
-       quiesce_rx(adapter);
        t4_sge_stop(adapter);
        t4_free_sge_resources(adapter);
        adapter->flags &= ~FULL_INIT_DONE;
@@ -4733,8 +4754,9 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
        if (ret < 0)
                return ret;
 
-       ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, MAX_EGRQ, 64, MAX_INGQ,
-                         0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, FW_CMD_CAP_PF);
+       ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, adap->sge.egr_sz, 64,
+                         MAX_INGQ, 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF,
+                         FW_CMD_CAP_PF);
        if (ret < 0)
                return ret;
 
@@ -5088,10 +5110,15 @@ static int adap_init0(struct adapter *adap)
        enum dev_state state;
        u32 params[7], val[7];
        struct fw_caps_config_cmd caps_cmd;
-       struct fw_devlog_cmd devlog_cmd;
-       u32 devlog_meminfo;
        int reset = 1;
 
+       /* Grab Firmware Device Log parameters as early as possible so we have
+        * access to it for debugging, etc.
+        */
+       ret = t4_init_devlog_params(adap);
+       if (ret < 0)
+               return ret;
+
        /* Contact FW, advertising Master capability */
        ret = t4_fw_hello(adap, adap->mbox, adap->mbox, MASTER_MAY, &state);
        if (ret < 0) {
@@ -5169,30 +5196,6 @@ static int adap_init0(struct adapter *adap)
        if (ret < 0)
                goto bye;
 
-       /* Read firmware device log parameters.  We really need to find a way
-        * to get these parameters initialized with some default values (which
-        * are likely to be correct) for the case where we either don't
-        * attache to the firmware or it's crashed when we probe the adapter.
-        * That way we'll still be able to perform early firmware startup
-        * debugging ...  If the request to get the Firmware's Device Log
-        * parameters fails, we'll live so we don't make that a fatal error.
-        */
-       memset(&devlog_cmd, 0, sizeof(devlog_cmd));
-       devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) |
-                                      FW_CMD_REQUEST_F | FW_CMD_READ_F);
-       devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd));
-       ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd),
-                        &devlog_cmd);
-       if (ret == 0) {
-               devlog_meminfo =
-                       ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog);
-               adap->params.devlog.memtype =
-                       FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo);
-               adap->params.devlog.start =
-                       FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4;
-               adap->params.devlog.size = ntohl(devlog_cmd.memsize_devlog);
-       }
-
        /*
         * Find out what ports are available to us.  Note that we need to do
         * this before calling adap_init0_no_config() since it needs nports
@@ -5293,6 +5296,51 @@ static int adap_init0(struct adapter *adap)
        adap->tids.nftids = val[4] - val[3] + 1;
        adap->sge.ingr_start = val[5];
 
+       /* qids (ingress/egress) returned from firmware can be anywhere
+        * in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END.
+        * Hence driver needs to allocate memory for this range to
+        * store the queue info. Get the highest IQFLINT/EQ index returned
+        * in FW_EQ_*_CMD.alloc command.
+        */
+       params[0] = FW_PARAM_PFVF(EQ_END);
+       params[1] = FW_PARAM_PFVF(IQFLINT_END);
+       ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
+       if (ret < 0)
+               goto bye;
+       adap->sge.egr_sz = val[0] - adap->sge.egr_start + 1;
+       adap->sge.ingr_sz = val[1] - adap->sge.ingr_start + 1;
+
+       adap->sge.egr_map = kcalloc(adap->sge.egr_sz,
+                                   sizeof(*adap->sge.egr_map), GFP_KERNEL);
+       if (!adap->sge.egr_map) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
+       adap->sge.ingr_map = kcalloc(adap->sge.ingr_sz,
+                                    sizeof(*adap->sge.ingr_map), GFP_KERNEL);
+       if (!adap->sge.ingr_map) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
+       /* Allocate the memory for the vaious egress queue bitmaps
+        * ie starving_fl and txq_maperr.
+        */
+       adap->sge.starving_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
+                                       sizeof(long), GFP_KERNEL);
+       if (!adap->sge.starving_fl) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
+       adap->sge.txq_maperr = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
+                                      sizeof(long), GFP_KERNEL);
+       if (!adap->sge.txq_maperr) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
        params[0] = FW_PARAM_PFVF(CLIP_START);
        params[1] = FW_PARAM_PFVF(CLIP_END);
        ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
@@ -5501,6 +5549,10 @@ static int adap_init0(struct adapter *adap)
         * happened to HW/FW, stop issuing commands.
         */
 bye:
+       kfree(adap->sge.egr_map);
+       kfree(adap->sge.ingr_map);
+       kfree(adap->sge.starving_fl);
+       kfree(adap->sge.txq_maperr);
        if (ret != -ETIMEDOUT && ret != -EIO)
                t4_fw_bye(adap, adap->mbox);
        return ret;
@@ -5528,6 +5580,7 @@ static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev,
                netif_carrier_off(dev);
        }
        spin_unlock(&adap->stats_lock);
+       disable_interrupts(adap);
        if (adap->flags & FULL_INIT_DONE)
                cxgb_down(adap);
        rtnl_unlock();
@@ -5912,6 +5965,10 @@ static void free_some_resources(struct adapter *adapter)
 
        t4_free_mem(adapter->l2t);
        t4_free_mem(adapter->tids.tid_tab);
+       kfree(adapter->sge.egr_map);
+       kfree(adapter->sge.ingr_map);
+       kfree(adapter->sge.starving_fl);
+       kfree(adapter->sge.txq_maperr);
        disable_msi(adapter);
 
        for_each_port(adapter, i)
@@ -6237,6 +6294,8 @@ static void remove_one(struct pci_dev *pdev)
                if (is_offload(adapter))
                        detach_ulds(adapter);
 
+               disable_interrupts(adapter);
+
                for_each_port(adapter, i)
                        if (adapter->port[i]->reg_state == NETREG_REGISTERED)
                                unregister_netdev(adapter->port[i]);
index b4b9f60..b688b32 100644 (file)
@@ -2171,7 +2171,7 @@ static void sge_rx_timer_cb(unsigned long data)
        struct adapter *adap = (struct adapter *)data;
        struct sge *s = &adap->sge;
 
-       for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++)
+       for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++)
                for (m = s->starving_fl[i]; m; m &= m - 1) {
                        struct sge_eth_rxq *rxq;
                        unsigned int id = __ffs(m) + i * BITS_PER_LONG;
@@ -2259,7 +2259,7 @@ static void sge_tx_timer_cb(unsigned long data)
        struct adapter *adap = (struct adapter *)data;
        struct sge *s = &adap->sge;
 
-       for (i = 0; i < ARRAY_SIZE(s->txq_maperr); i++)
+       for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++)
                for (m = s->txq_maperr[i]; m; m &= m - 1) {
                        unsigned long id = __ffs(m) + i * BITS_PER_LONG;
                        struct sge_ofld_txq *txq = s->egr_map[id];
@@ -2741,7 +2741,8 @@ void t4_free_sge_resources(struct adapter *adap)
                free_rspq_fl(adap, &adap->sge.intrq, NULL);
 
        /* clear the reverse egress queue map */
-       memset(adap->sge.egr_map, 0, sizeof(adap->sge.egr_map));
+       memset(adap->sge.egr_map, 0,
+              adap->sge.egr_sz * sizeof(*adap->sge.egr_map));
 }
 
 void t4_sge_start(struct adapter *adap)
index 853c389..ee394dc 100644 (file)
@@ -1120,7 +1120,7 @@ int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info,
                }
 
                /* Installed successfully, update the cached header too. */
-               memcpy(card_fw, fs_fw, sizeof(*card_fw));
+               *card_fw = *fs_fw;
                card_fw_usable = 1;
                *reset = 0;     /* already reset as part of load_fw */
        }
@@ -4459,6 +4459,59 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
 }
 
 /**
+ *     t4_init_devlog_params - initialize adapter->params.devlog
+ *     @adap: the adapter
+ *
+ *     Initialize various fields of the adapter's Firmware Device Log
+ *     Parameters structure.
+ */
+int t4_init_devlog_params(struct adapter *adap)
+{
+       struct devlog_params *dparams = &adap->params.devlog;
+       u32 pf_dparams;
+       unsigned int devlog_meminfo;
+       struct fw_devlog_cmd devlog_cmd;
+       int ret;
+
+       /* If we're dealing with newer firmware, the Device Log Paramerters
+        * are stored in a designated register which allows us to access the
+        * Device Log even if we can't talk to the firmware.
+        */
+       pf_dparams =
+               t4_read_reg(adap, PCIE_FW_REG(PCIE_FW_PF_A, PCIE_FW_PF_DEVLOG));
+       if (pf_dparams) {
+               unsigned int nentries, nentries128;
+
+               dparams->memtype = PCIE_FW_PF_DEVLOG_MEMTYPE_G(pf_dparams);
+               dparams->start = PCIE_FW_PF_DEVLOG_ADDR16_G(pf_dparams) << 4;
+
+               nentries128 = PCIE_FW_PF_DEVLOG_NENTRIES128_G(pf_dparams);
+               nentries = (nentries128 + 1) * 128;
+               dparams->size = nentries * sizeof(struct fw_devlog_e);
+
+               return 0;
+       }
+
+       /* Otherwise, ask the firmware for it's Device Log Parameters.
+        */
+       memset(&devlog_cmd, 0, sizeof(devlog_cmd));
+       devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) |
+                                      FW_CMD_REQUEST_F | FW_CMD_READ_F);
+       devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd));
+       ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd),
+                        &devlog_cmd);
+       if (ret)
+               return ret;
+
+       devlog_meminfo = ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog);
+       dparams->memtype = FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo);
+       dparams->start = FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4;
+       dparams->size = ntohl(devlog_cmd.memsize_devlog);
+
+       return 0;
+}
+
+/**
  *     t4_init_sge_params - initialize adap->params.sge
  *     @adapter: the adapter
  *
index 231a725..326674b 100644 (file)
@@ -63,6 +63,8 @@
 #define MC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
 #define EDC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
 
+#define PCIE_FW_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
+
 #define SGE_PF_KDOORBELL_A 0x0
 
 #define QID_S    15
 #define PFNUM_V(x) ((x) << PFNUM_S)
 
 #define PCIE_FW_A 0x30b8
+#define PCIE_FW_PF_A 0x30bc
 
 #define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A 0x5908
 
index 9b353a8..a4a19e0 100644 (file)
@@ -101,7 +101,7 @@ enum fw_wr_opcodes {
        FW_RI_BIND_MW_WR               = 0x18,
        FW_RI_FR_NSMR_WR               = 0x19,
        FW_RI_INV_LSTAG_WR             = 0x1a,
-       FW_LASTC2E_WR                  = 0x40
+       FW_LASTC2E_WR                  = 0x70
 };
 
 struct fw_wr_hdr {
@@ -993,6 +993,7 @@ enum fw_memtype_cf {
        FW_MEMTYPE_CF_EXTMEM            = 0x2,
        FW_MEMTYPE_CF_FLASH             = 0x4,
        FW_MEMTYPE_CF_INTERNAL          = 0x5,
+       FW_MEMTYPE_CF_EXTMEM1           = 0x6,
 };
 
 struct fw_caps_config_cmd {
@@ -1035,6 +1036,7 @@ enum fw_params_mnem {
        FW_PARAMS_MNEM_PFVF             = 2,    /* function params */
        FW_PARAMS_MNEM_REG              = 3,    /* limited register access */
        FW_PARAMS_MNEM_DMAQ             = 4,    /* dma queue params */
+       FW_PARAMS_MNEM_CHNET            = 5,    /* chnet params */
        FW_PARAMS_MNEM_LAST
 };
 
@@ -3102,7 +3104,8 @@ enum fw_devlog_facility {
        FW_DEVLOG_FACILITY_FCOE         = 0x2E,
        FW_DEVLOG_FACILITY_FOISCSI      = 0x30,
        FW_DEVLOG_FACILITY_FOFCOE       = 0x32,
-       FW_DEVLOG_FACILITY_MAX          = 0x32,
+       FW_DEVLOG_FACILITY_CHNET        = 0x34,
+       FW_DEVLOG_FACILITY_MAX          = 0x34,
 };
 
 /* log message format */
@@ -3139,4 +3142,36 @@ struct fw_devlog_cmd {
        (((x) >> FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S) & \
         FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M)
 
+/* P C I E   F W   P F 7   R E G I S T E R */
+
+/* PF7 stores the Firmware Device Log parameters which allows Host Drivers to
+ * access the "devlog" which needing to contact firmware.  The encoding is
+ * mostly the same as that returned by the DEVLOG command except for the size
+ * which is encoded as the number of entries in multiples-1 of 128 here rather
+ * than the memory size as is done in the DEVLOG command.  Thus, 0 means 128
+ * and 15 means 2048.  This of course in turn constrains the allowed values
+ * for the devlog size ...
+ */
+#define PCIE_FW_PF_DEVLOG              7
+
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_S        28
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_M        0xf
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_V(x) \
+       ((x) << PCIE_FW_PF_DEVLOG_NENTRIES128_S)
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_G(x) \
+       (((x) >> PCIE_FW_PF_DEVLOG_NENTRIES128_S) & \
+        PCIE_FW_PF_DEVLOG_NENTRIES128_M)
+
+#define PCIE_FW_PF_DEVLOG_ADDR16_S     4
+#define PCIE_FW_PF_DEVLOG_ADDR16_M     0xffffff
+#define PCIE_FW_PF_DEVLOG_ADDR16_V(x)  ((x) << PCIE_FW_PF_DEVLOG_ADDR16_S)
+#define PCIE_FW_PF_DEVLOG_ADDR16_G(x) \
+       (((x) >> PCIE_FW_PF_DEVLOG_ADDR16_S) & PCIE_FW_PF_DEVLOG_ADDR16_M)
+
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_S    0
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_M    0xf
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_V(x) ((x) << PCIE_FW_PF_DEVLOG_MEMTYPE_S)
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_G(x) \
+       (((x) >> PCIE_FW_PF_DEVLOG_MEMTYPE_S) & PCIE_FW_PF_DEVLOG_MEMTYPE_M)
+
 #endif /* _T4FW_INTERFACE_H_ */
index e2bd3f7..b9d1cba 100644 (file)
 #define __T4FW_VERSION_H__
 
 #define T4FW_VERSION_MAJOR 0x01
-#define T4FW_VERSION_MINOR 0x0C
-#define T4FW_VERSION_MICRO 0x19
+#define T4FW_VERSION_MINOR 0x0D
+#define T4FW_VERSION_MICRO 0x20
 #define T4FW_VERSION_BUILD 0x00
 
 #define T5FW_VERSION_MAJOR 0x01
-#define T5FW_VERSION_MINOR 0x0C
-#define T5FW_VERSION_MICRO 0x19
+#define T5FW_VERSION_MINOR 0x0D
+#define T5FW_VERSION_MICRO 0x20
 #define T5FW_VERSION_BUILD 0x00
 
 #endif
index 0545f0d..e0d7110 100644 (file)
@@ -1004,7 +1004,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
                                              ? (tq->pidx - 1)
                                              : (tq->size - 1));
                        __be64 *src = (__be64 *)&tq->desc[index];
-                       __be64 __iomem *dst = (__be64 *)(tq->bar2_addr +
+                       __be64 __iomem *dst = (__be64 __iomem *)(tq->bar2_addr +
                                                         SGE_UDB_WCDOORBELL);
                        unsigned int count = EQ_UNIT / sizeof(__be64);
 
@@ -1018,7 +1018,11 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
                         * DMA.
                         */
                        while (count) {
-                               writeq(*src, dst);
+                               /* the (__force u64) is because the compiler
+                                * doesn't understand the endian swizzling
+                                * going on
+                                */
+                               writeq((__force u64)*src, dst);
                                src++;
                                dst++;
                                count--;
@@ -1252,8 +1256,8 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        BUG_ON(DIV_ROUND_UP(ETHTXQ_MAX_HDR, TXD_PER_EQ_UNIT) > 1);
        wr = (void *)&txq->q.desc[txq->q.pidx];
        wr->equiq_to_len16 = cpu_to_be32(wr_mid);
-       wr->r3[0] = cpu_to_be64(0);
-       wr->r3[1] = cpu_to_be64(0);
+       wr->r3[0] = cpu_to_be32(0);
+       wr->r3[1] = cpu_to_be32(0);
        skb_copy_from_linear_data(skb, (void *)wr->ethmacdst, fw_hdr_copy_len);
        end = (u64 *)wr + flits;
 
index 1b5506d..280b4a2 100644 (file)
@@ -210,10 +210,10 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
 
                        if (rpl) {
                                /* request bit in high-order BE word */
-                               WARN_ON((be32_to_cpu(*(const u32 *)cmd)
+                               WARN_ON((be32_to_cpu(*(const __be32 *)cmd)
                                         & FW_CMD_REQUEST_F) == 0);
                                get_mbox_rpl(adapter, rpl, size, mbox_data);
-                               WARN_ON((be32_to_cpu(*(u32 *)rpl)
+                               WARN_ON((be32_to_cpu(*(__be32 *)rpl)
                                         & FW_CMD_REQUEST_F) != 0);
                        }
                        t4_write_reg(adapter, mbox_ctl,
@@ -484,7 +484,7 @@ int t4_bar2_sge_qregs(struct adapter *adapter,
         *  o The BAR2 Queue ID.
         *  o The BAR2 Queue ID Offset into the BAR2 page.
         */
-       bar2_page_offset = ((qid >> qpp_shift) << page_shift);
+       bar2_page_offset = ((u64)(qid >> qpp_shift) << page_shift);
        bar2_qid = qid & qpp_mask;
        bar2_qid_offset = bar2_qid * SGE_UDB_SIZE;
 
index 3b42556..ed41559 100644 (file)
@@ -589,7 +589,7 @@ static void tulip_tx_timeout(struct net_device *dev)
                               (unsigned int)tp->rx_ring[i].buffer1,
                               (unsigned int)tp->rx_ring[i].buffer2,
                               buf[0], buf[1], buf[2]);
-                       for (j = 0; buf[j] != 0xee && j < 1600; j++)
+                       for (j = 0; ((j < 1600) && buf[j] != 0xee); j++)
                                if (j < 100)
                                        pr_cont(" %02x", buf[j]);
                        pr_cont(" j=%d\n", j);
index 27de37a..27b9fe9 100644 (file)
@@ -354,6 +354,7 @@ struct be_vf_cfg {
        u16 vlan_tag;
        u32 tx_rate;
        u32 plink_tracking;
+       u32 privileges;
 };
 
 enum vf_state {
@@ -423,6 +424,7 @@ struct be_adapter {
 
        u8 __iomem *csr;        /* CSR BAR used only for BE2/3 */
        u8 __iomem *db;         /* Door Bell */
+       u8 __iomem *pcicfg;     /* On SH,BEx only. Shadow of PCI config space */
 
        struct mutex mbox_lock; /* For serializing mbox cmds to BE card */
        struct be_dma_mem mbox_mem;
index 36916cf..7f05f30 100644 (file)
@@ -1902,15 +1902,11 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,
 {
        int num_eqs, i = 0;
 
-       if (lancer_chip(adapter) && num > 8) {
-               while (num) {
-                       num_eqs = min(num, 8);
-                       __be_cmd_modify_eqd(adapter, &set_eqd[i], num_eqs);
-                       i += num_eqs;
-                       num -= num_eqs;
-               }
-       } else {
-               __be_cmd_modify_eqd(adapter, set_eqd, num);
+       while (num) {
+               num_eqs = min(num, 8);
+               __be_cmd_modify_eqd(adapter, &set_eqd[i], num_eqs);
+               i += num_eqs;
+               num -= num_eqs;
        }
 
        return 0;
@@ -1918,7 +1914,7 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,
 
 /* Uses sycnhronous mcc */
 int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
-                      u32 num)
+                      u32 num, u32 domain)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_vlan_config *req;
@@ -1936,6 +1932,7 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
        be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                               OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req),
                               wrb, NULL);
+       req->hdr.domain = domain;
 
        req->interface_id = if_id;
        req->untagged = BE_IF_FLAGS_UNTAGGED & be_if_cap_flags(adapter) ? 1 : 0;
index db761e8..a7634a3 100644 (file)
@@ -2256,7 +2256,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
 int be_cmd_get_fw_ver(struct be_adapter *adapter);
 int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *, int num);
 int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
-                      u32 num);
+                      u32 num, u32 domain);
 int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status);
 int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc);
 int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc);
index 0a81685..e6b790f 100644 (file)
@@ -1171,7 +1171,7 @@ static int be_vid_config(struct be_adapter *adapter)
        for_each_set_bit(i, adapter->vids, VLAN_N_VID)
                vids[num++] = cpu_to_le16(i);
 
-       status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num);
+       status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num, 0);
        if (status) {
                dev_err(dev, "Setting HW VLAN filtering failed\n");
                /* Set to VLAN promisc mode as setting VLAN filter failed */
@@ -1380,11 +1380,67 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
        return 0;
 }
 
+static int be_set_vf_tvt(struct be_adapter *adapter, int vf, u16 vlan)
+{
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
+       u16 vids[BE_NUM_VLANS_SUPPORTED];
+       int vf_if_id = vf_cfg->if_handle;
+       int status;
+
+       /* Enable Transparent VLAN Tagging */
+       status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, vf_if_id, 0);
+       if (status)
+               return status;
+
+       /* Clear pre-programmed VLAN filters on VF if any, if TVT is enabled */
+       vids[0] = 0;
+       status = be_cmd_vlan_config(adapter, vf_if_id, vids, 1, vf + 1);
+       if (!status)
+               dev_info(&adapter->pdev->dev,
+                        "Cleared guest VLANs on VF%d", vf);
+
+       /* After TVT is enabled, disallow VFs to program VLAN filters */
+       if (vf_cfg->privileges & BE_PRIV_FILTMGMT) {
+               status = be_cmd_set_fn_privileges(adapter, vf_cfg->privileges &
+                                                 ~BE_PRIV_FILTMGMT, vf + 1);
+               if (!status)
+                       vf_cfg->privileges &= ~BE_PRIV_FILTMGMT;
+       }
+       return 0;
+}
+
+static int be_clear_vf_tvt(struct be_adapter *adapter, int vf)
+{
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
+       struct device *dev = &adapter->pdev->dev;
+       int status;
+
+       /* Reset Transparent VLAN Tagging. */
+       status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID, vf + 1,
+                                      vf_cfg->if_handle, 0);
+       if (status)
+               return status;
+
+       /* Allow VFs to program VLAN filtering */
+       if (!(vf_cfg->privileges & BE_PRIV_FILTMGMT)) {
+               status = be_cmd_set_fn_privileges(adapter, vf_cfg->privileges |
+                                                 BE_PRIV_FILTMGMT, vf + 1);
+               if (!status) {
+                       vf_cfg->privileges |= BE_PRIV_FILTMGMT;
+                       dev_info(dev, "VF%d: FILTMGMT priv enabled", vf);
+               }
+       }
+
+       dev_info(dev,
+                "Disable/re-enable i/f in VM to clear Transparent VLAN tag");
+       return 0;
+}
+
 static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
        struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
-       int status = 0;
+       int status;
 
        if (!sriov_enabled(adapter))
                return -EPERM;
@@ -1394,24 +1450,19 @@ static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
 
        if (vlan || qos) {
                vlan |= qos << VLAN_PRIO_SHIFT;
-               if (vf_cfg->vlan_tag != vlan)
-                       status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
-                                                      vf_cfg->if_handle, 0);
+               status = be_set_vf_tvt(adapter, vf, vlan);
        } else {
-               /* Reset Transparent Vlan Tagging. */
-               status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
-                                              vf + 1, vf_cfg->if_handle, 0);
+               status = be_clear_vf_tvt(adapter, vf);
        }
 
        if (status) {
                dev_err(&adapter->pdev->dev,
-                       "VLAN %d config on VF %d failed : %#x\n", vlan,
-                       vf, status);
+                       "VLAN %d config on VF %d failed : %#x\n", vlan, vf,
+                       status);
                return be_cmd_status(status);
        }
 
        vf_cfg->vlan_tag = vlan;
-
        return 0;
 }
 
@@ -2772,14 +2823,12 @@ void be_detect_error(struct be_adapter *adapter)
                        }
                }
        } else {
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_LOW, &ue_lo);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_HIGH, &ue_hi);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_LOW_MASK, &ue_lo_mask);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_HI_MASK, &ue_hi_mask);
+               ue_lo = ioread32(adapter->pcicfg + PCICFG_UE_STATUS_LOW);
+               ue_hi = ioread32(adapter->pcicfg + PCICFG_UE_STATUS_HIGH);
+               ue_lo_mask = ioread32(adapter->pcicfg +
+                                     PCICFG_UE_STATUS_LOW_MASK);
+               ue_hi_mask = ioread32(adapter->pcicfg +
+                                     PCICFG_UE_STATUS_HI_MASK);
 
                ue_lo = (ue_lo & ~ue_lo_mask);
                ue_hi = (ue_hi & ~ue_hi_mask);
@@ -3339,7 +3388,6 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
                        u32 cap_flags, u32 vf)
 {
        u32 en_flags;
-       int status;
 
        en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                   BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
@@ -3347,10 +3395,7 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
 
        en_flags &= cap_flags;
 
-       status = be_cmd_if_create(adapter, cap_flags, en_flags,
-                                 if_handle, vf);
-
-       return status;
+       return be_cmd_if_create(adapter, cap_flags, en_flags, if_handle, vf);
 }
 
 static int be_vfs_if_create(struct be_adapter *adapter)
@@ -3368,8 +3413,13 @@ static int be_vfs_if_create(struct be_adapter *adapter)
                if (!BE3_chip(adapter)) {
                        status = be_cmd_get_profile_config(adapter, &res,
                                                           vf + 1);
-                       if (!status)
+                       if (!status) {
                                cap_flags = res.if_cap_flags;
+                               /* Prevent VFs from enabling VLAN promiscuous
+                                * mode
+                                */
+                               cap_flags &= ~BE_IF_FLAGS_VLAN_PROMISCUOUS;
+                       }
                }
 
                status = be_if_create(adapter, &vf_cfg->if_handle,
@@ -3403,7 +3453,6 @@ static int be_vf_setup(struct be_adapter *adapter)
        struct device *dev = &adapter->pdev->dev;
        struct be_vf_cfg *vf_cfg;
        int status, old_vfs, vf;
-       u32 privileges;
 
        old_vfs = pci_num_vf(adapter->pdev);
 
@@ -3433,15 +3482,18 @@ static int be_vf_setup(struct be_adapter *adapter)
 
        for_all_vfs(adapter, vf_cfg, vf) {
                /* Allow VFs to programs MAC/VLAN filters */
-               status = be_cmd_get_fn_privileges(adapter, &privileges, vf + 1);
-               if (!status && !(privileges & BE_PRIV_FILTMGMT)) {
+               status = be_cmd_get_fn_privileges(adapter, &vf_cfg->privileges,
+                                                 vf + 1);
+               if (!status && !(vf_cfg->privileges & BE_PRIV_FILTMGMT)) {
                        status = be_cmd_set_fn_privileges(adapter,
-                                                         privileges |
+                                                         vf_cfg->privileges |
                                                          BE_PRIV_FILTMGMT,
                                                          vf + 1);
-                       if (!status)
+                       if (!status) {
+                               vf_cfg->privileges |= BE_PRIV_FILTMGMT;
                                dev_info(dev, "VF%d has FILTMGMT privilege\n",
                                         vf);
+                       }
                }
 
                /* Allow full available bandwidth */
@@ -4820,24 +4872,37 @@ static int be_roce_map_pci_bars(struct be_adapter *adapter)
 
 static int be_map_pci_bars(struct be_adapter *adapter)
 {
+       struct pci_dev *pdev = adapter->pdev;
        u8 __iomem *addr;
 
        if (BEx_chip(adapter) && be_physfn(adapter)) {
-               adapter->csr = pci_iomap(adapter->pdev, 2, 0);
+               adapter->csr = pci_iomap(pdev, 2, 0);
                if (!adapter->csr)
                        return -ENOMEM;
        }
 
-       addr = pci_iomap(adapter->pdev, db_bar(adapter), 0);
+       addr = pci_iomap(pdev, db_bar(adapter), 0);
        if (!addr)
                goto pci_map_err;
        adapter->db = addr;
 
+       if (skyhawk_chip(adapter) || BEx_chip(adapter)) {
+               if (be_physfn(adapter)) {
+                       /* PCICFG is the 2nd BAR in BE2 */
+                       addr = pci_iomap(pdev, BE2_chip(adapter) ? 1 : 0, 0);
+                       if (!addr)
+                               goto pci_map_err;
+                       adapter->pcicfg = addr;
+               } else {
+                       adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
+               }
+       }
+
        be_roce_map_pci_bars(adapter);
        return 0;
 
 pci_map_err:
-       dev_err(&adapter->pdev->dev, "Error in mapping PCI BARs\n");
+       dev_err(&pdev->dev, "Error in mapping PCI BARs\n");
        be_unmap_pci_bars(adapter);
        return -ENOMEM;
 }
index 99492b7..f6a3a7a 100644 (file)
@@ -1189,13 +1189,12 @@ static void
 fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
 {
        struct  fec_enet_private *fep;
-       struct bufdesc *bdp, *bdp_t;
+       struct bufdesc *bdp;
        unsigned short status;
        struct  sk_buff *skb;
        struct fec_enet_priv_tx_q *txq;
        struct netdev_queue *nq;
        int     index = 0;
-       int     i, bdnum;
        int     entries_free;
 
        fep = netdev_priv(ndev);
@@ -1216,29 +1215,18 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
                if (bdp == txq->cur_tx)
                        break;
 
-               bdp_t = bdp;
-               bdnum = 1;
-               index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep);
-               skb = txq->tx_skbuff[index];
-               while (!skb) {
-                       bdp_t = fec_enet_get_nextdesc(bdp_t, fep, queue_id);
-                       index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep);
-                       skb = txq->tx_skbuff[index];
-                       bdnum++;
-               }
-               if (skb_shinfo(skb)->nr_frags &&
-                   (status = bdp_t->cbd_sc) & BD_ENET_TX_READY)
-                       break;
+               index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 
-               for (i = 0; i < bdnum; i++) {
-                       if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
-                               dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
-                                                bdp->cbd_datlen, DMA_TO_DEVICE);
-                       bdp->cbd_bufaddr = 0;
-                       if (i < bdnum - 1)
-                               bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
-               }
+               skb = txq->tx_skbuff[index];
                txq->tx_skbuff[index] = NULL;
+               if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
+                       dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
+                                       bdp->cbd_datlen, DMA_TO_DEVICE);
+               bdp->cbd_bufaddr = 0;
+               if (!skb) {
+                       bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
+                       continue;
+               }
 
                /* Check for errors. */
                if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
@@ -1479,8 +1467,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 
                        vlan_packet_rcvd = true;
 
-                       skb_copy_to_linear_data_offset(skb, VLAN_HLEN,
-                                                      data, (2 * ETH_ALEN));
+                       memmove(skb->data + VLAN_HLEN, data, ETH_ALEN * 2);
                        skb_pull(skb, VLAN_HLEN);
                }
 
@@ -1967,6 +1954,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        struct device_node *node;
        int err = -ENXIO, i;
+       u32 mii_speed, holdtime;
 
        /*
         * The i.MX28 dual fec interfaces are not equal.
@@ -2004,10 +1992,33 @@ static int fec_enet_mii_init(struct platform_device *pdev)
         * Reference Manual has an error on this, and gets fixed on i.MX6Q
         * document.
         */
-       fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
+       mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
        if (fep->quirks & FEC_QUIRK_ENET_MAC)
-               fep->phy_speed--;
-       fep->phy_speed <<= 1;
+               mii_speed--;
+       if (mii_speed > 63) {
+               dev_err(&pdev->dev,
+                       "fec clock (%lu) to fast to get right mii speed\n",
+                       clk_get_rate(fep->clk_ipg));
+               err = -EINVAL;
+               goto err_out;
+       }
+
+       /*
+        * The i.MX28 and i.MX6 types have another filed in the MSCR (aka
+        * MII_SPEED) register that defines the MDIO output hold time. Earlier
+        * versions are RAZ there, so just ignore the difference and write the
+        * register always.
+        * The minimal hold time according to IEE802.3 (clause 22) is 10 ns.
+        * HOLDTIME + 1 is the number of clk cycles the fec is holding the
+        * output.
+        * The HOLDTIME bitfield takes values between 0 and 7 (inclusive).
+        * Given that ceil(clkrate / 5000000) <= 64, the calculation for
+        * holdtime cannot result in a value greater than 3.
+        */
+       holdtime = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 100000000) - 1;
+
+       fep->phy_speed = mii_speed << 1 | holdtime << 8;
+
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
        fep->mii_bus = mdiobus_alloc();
index 357e8b5..56b774d 100644 (file)
@@ -3893,6 +3893,9 @@ static int ucc_geth_probe(struct platform_device* ofdev)
        ugeth->phy_interface = phy_interface;
        ugeth->max_speed = max_speed;
 
+       /* Carrier starts down, phylib will bring it up */
+       netif_carrier_off(dev);
+
        err = register_netdev(dev);
        if (err) {
                if (netif_msg_probe(ugeth))
index 072426a..cd7675a 100644 (file)
@@ -1136,6 +1136,8 @@ restart_poll:
        ibmveth_replenish_task(adapter);
 
        if (frames_processed < budget) {
+               napi_complete(napi);
+
                /* We think we are done - reenable interrupts,
                 * then check once more to make sure we are done.
                 */
@@ -1144,8 +1146,6 @@ restart_poll:
 
                BUG_ON(lpar_rc != H_SUCCESS);
 
-               napi_complete(napi);
-
                if (ibmveth_rxq_pending_buffer(adapter) &&
                    napi_reschedule(napi)) {
                        lpar_rc = h_vio_signal(adapter->vdev->unit_address,
index 96208f1..2db6532 100644 (file)
@@ -2658,16 +2658,11 @@ static int mvneta_stop(struct net_device *dev)
 static int mvneta_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct mvneta_port *pp = netdev_priv(dev);
-       int ret;
 
        if (!pp->phy_dev)
                return -ENOTSUPP;
 
-       ret = phy_mii_ioctl(pp->phy_dev, ifr, cmd);
-       if (!ret)
-               mvneta_adjust_link(dev);
-
-       return ret;
+       return phy_mii_ioctl(pp->phy_dev, ifr, cmd);
 }
 
 /* Ethtool methods */
index a681d7c..546ca42 100644 (file)
@@ -724,7 +724,8 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
                 * on the host, we deprecate the error message for this
                 * specific command/input_mod/opcode_mod/fw-status to be debug.
                 */
-               if (op == MLX4_CMD_SET_PORT && in_modifier == 1 &&
+               if (op == MLX4_CMD_SET_PORT &&
+                   (in_modifier == 1 || in_modifier == 2) &&
                    op_modifier == 0 && context->fw_status == CMD_STAT_BAD_SIZE)
                        mlx4_dbg(dev, "command 0x%x failed: fw status = 0x%x\n",
                                 op, context->fw_status);
@@ -1993,7 +1994,6 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
                        goto reset_slave;
                slave_state[slave].vhcr_dma = ((u64) param) << 48;
                priv->mfunc.master.slave_state[slave].cookie = 0;
-               mutex_init(&priv->mfunc.master.gen_eqe_mutex[slave]);
                break;
        case MLX4_COMM_CMD_VHCR1:
                if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0)
@@ -2225,6 +2225,7 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
                for (i = 0; i < dev->num_slaves; ++i) {
                        s_state = &priv->mfunc.master.slave_state[i];
                        s_state->last_cmd = MLX4_COMM_CMD_RESET;
+                       mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]);
                        for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j)
                                s_state->event_eq[j].eqn = -1;
                        __raw_writel((__force u32) 0,
index 2a210c4..3485acf 100644 (file)
@@ -1698,8 +1698,6 @@ int mlx4_en_start_port(struct net_device *dev)
        /* Schedule multicast task to populate multicast list */
        queue_work(mdev->workqueue, &priv->rx_mode_task);
 
-       mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
-
 #ifdef CONFIG_MLX4_EN_VXLAN
        if (priv->mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
                vxlan_get_rx_port(dev);
@@ -2807,13 +2805,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        netif_carrier_off(dev);
        mlx4_en_set_default_moderation(priv);
 
-       err = register_netdev(dev);
-       if (err) {
-               en_err(priv, "Netdev registration failed for port %d\n", port);
-               goto out;
-       }
-       priv->registered = 1;
-
        en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
        en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
 
@@ -2853,6 +2844,16 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
                queue_delayed_work(mdev->workqueue, &priv->service_task,
                                   SERVICE_TASK_DELAY);
 
+       mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
+
+       err = register_netdev(dev);
+       if (err) {
+               en_err(priv, "Netdev registration failed for port %d\n", port);
+               goto out;
+       }
+
+       priv->registered = 1;
+
        return 0;
 
 out:
index 264bc15..6e70ffe 100644 (file)
@@ -153,12 +153,10 @@ void mlx4_gen_slave_eqe(struct work_struct *work)
 
                /* All active slaves need to receive the event */
                if (slave == ALL_SLAVES) {
-                       for (i = 0; i < dev->num_slaves; i++) {
-                               if (i != dev->caps.function &&
-                                   master->slave_state[i].active)
-                                       if (mlx4_GEN_EQE(dev, i, eqe))
-                                               mlx4_warn(dev, "Failed to generate event for slave %d\n",
-                                                         i);
+                       for (i = 0; i <= dev->persist->num_vfs; i++) {
+                               if (mlx4_GEN_EQE(dev, i, eqe))
+                                       mlx4_warn(dev, "Failed to generate event for slave %d\n",
+                                                 i);
                        }
                } else {
                        if (mlx4_GEN_EQE(dev, slave, eqe))
@@ -203,13 +201,11 @@ static void mlx4_slave_event(struct mlx4_dev *dev, int slave,
                             struct mlx4_eqe *eqe)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       struct mlx4_slave_state *s_slave =
-               &priv->mfunc.master.slave_state[slave];
 
-       if (!s_slave->active) {
-               /*mlx4_warn(dev, "Trying to pass event to inactive slave\n");*/
+       if (slave < 0 || slave > dev->persist->num_vfs ||
+           slave == dev->caps.function ||
+           !priv->mfunc.master.slave_state[slave].active)
                return;
-       }
 
        slave_event(dev, slave, eqe);
 }
index 2a8268e..ebbe244 100644 (file)
@@ -453,7 +453,7 @@ struct mlx4_en_port_stats {
        unsigned long rx_chksum_none;
        unsigned long rx_chksum_complete;
        unsigned long tx_chksum_offload;
-#define NUM_PORT_STATS         9
+#define NUM_PORT_STATS         10
 };
 
 struct mlx4_en_perf_stats {
index d97ca88..6e413ac 100644 (file)
@@ -3095,6 +3095,12 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe)
        if (!priv->mfunc.master.slave_state)
                return -EINVAL;
 
+       /* check for slave valid, slave not PF, and slave active */
+       if (slave < 0 || slave > dev->persist->num_vfs ||
+           slave == dev->caps.function ||
+           !priv->mfunc.master.slave_state[slave].active)
+               return 0;
+
        event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type];
 
        /* Create the event only if the slave is registered */
index 9fb6948..5cecec2 100644 (file)
@@ -4468,10 +4468,16 @@ static int rocker_port_master_changed(struct net_device *dev)
        struct net_device *master = netdev_master_upper_dev_get(dev);
        int err = 0;
 
+       /* There are currently three cases handled here:
+        * 1. Joining a bridge
+        * 2. Leaving a previously joined bridge
+        * 3. Other, e.g. being added to or removed from a bond or openvswitch,
+        *    in which case nothing is done
+        */
        if (master && master->rtnl_link_ops &&
            !strcmp(master->rtnl_link_ops->kind, "bridge"))
                err = rocker_port_bridge_join(rocker_port, master);
-       else
+       else if (rocker_port_is_bridged(rocker_port))
                err = rocker_port_bridge_leave(rocker_port);
 
        return err;
index 5d093dc..8678e39 100644 (file)
@@ -2248,10 +2248,9 @@ static int smc_drv_probe(struct platform_device *pdev)
        const struct of_device_id *match = NULL;
        struct smc_local *lp;
        struct net_device *ndev;
-       struct resource *res;
+       struct resource *res, *ires;
        unsigned int __iomem *addr;
        unsigned long irq_flags = SMC_IRQ_FLAGS;
-       unsigned long irq_resflags;
        int ret;
 
        ndev = alloc_etherdev(sizeof(struct smc_local));
@@ -2343,19 +2342,16 @@ static int smc_drv_probe(struct platform_device *pdev)
                goto out_free_netdev;
        }
 
-       ndev->irq = platform_get_irq(pdev, 0);
-       if (ndev->irq <= 0) {
+       ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!ires) {
                ret = -ENODEV;
                goto out_release_io;
        }
-       /*
-        * If this platform does not specify any special irqflags, or if
-        * the resource supplies a trigger, override the irqflags with
-        * the trigger flags from the resource.
-        */
-       irq_resflags = irqd_get_trigger_type(irq_get_irq_data(ndev->irq));
-       if (irq_flags == -1 || irq_resflags & IRQF_TRIGGER_MASK)
-               irq_flags = irq_resflags & IRQF_TRIGGER_MASK;
+
+       ndev->irq = ires->start;
+
+       if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK)
+               irq_flags = ires->flags & IRQF_TRIGGER_MASK;
 
        ret = smc_request_attrib(pdev, ndev);
        if (ret)
index a495931..0e0fbb5 100644 (file)
@@ -498,9 +498,9 @@ static int w5100_napi_poll(struct napi_struct *napi, int budget)
        }
 
        if (rx_count < budget) {
+               napi_complete(napi);
                w5100_write(priv, W5100_IMR, IR_S0);
                mmiowb();
-               napi_complete(napi);
        }
 
        return rx_count;
index 09322d9..4b31000 100644 (file)
@@ -418,9 +418,9 @@ static int w5300_napi_poll(struct napi_struct *napi, int budget)
        }
 
        if (rx_count < budget) {
+               napi_complete(napi);
                w5300_write(priv, W5300_IMR, IR_S0);
                mmiowb();
-               napi_complete(napi);
        }
 
        return rx_count;
index 924ea98..54549a6 100644 (file)
@@ -114,7 +114,9 @@ unsigned int ipvlan_mac_hash(const unsigned char *addr);
 rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb);
 int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev);
 void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr);
-bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6);
+struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
+                                  const void *iaddr, bool is_v6);
+bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6);
 struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
                                        const void *iaddr, bool is_v6);
 void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync);
index 2a17500..b7877a1 100644 (file)
@@ -81,19 +81,20 @@ void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr)
        hash = (addr->atype == IPVL_IPV6) ?
               ipvlan_get_v6_hash(&addr->ip6addr) :
               ipvlan_get_v4_hash(&addr->ip4addr);
-       hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
+       if (hlist_unhashed(&addr->hlnode))
+               hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
 }
 
 void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync)
 {
-       hlist_del_rcu(&addr->hlnode);
+       hlist_del_init_rcu(&addr->hlnode);
        if (sync)
                synchronize_rcu();
 }
 
-bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
+struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
+                                  const void *iaddr, bool is_v6)
 {
-       struct ipvl_port *port = ipvlan->port;
        struct ipvl_addr *addr;
 
        list_for_each_entry(addr, &ipvlan->addrs, anode) {
@@ -101,12 +102,21 @@ bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
                    ipv6_addr_equal(&addr->ip6addr, iaddr)) ||
                    (!is_v6 && addr->atype == IPVL_IPV4 &&
                    addr->ip4addr.s_addr == ((struct in_addr *)iaddr)->s_addr))
-                       return true;
+                       return addr;
        }
+       return NULL;
+}
+
+bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6)
+{
+       struct ipvl_dev *ipvlan;
 
-       if (ipvlan_ht_addr_lookup(port, iaddr, is_v6))
-               return true;
+       ASSERT_RTNL();
 
+       list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
+               if (ipvlan_find_addr(ipvlan, iaddr, is_v6))
+                       return true;
+       }
        return false;
 }
 
@@ -192,7 +202,8 @@ static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb,
        if (skb->protocol == htons(ETH_P_PAUSE))
                return;
 
-       list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) {
                if (local && (ipvlan == in_dev))
                        continue;
 
@@ -219,6 +230,7 @@ static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb,
 mcast_acct:
                ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true);
        }
+       rcu_read_unlock();
 
        /* Locally generated? ...Forward a copy to the main-device as
         * well. On the RX side we'll ignore it (wont give it to any
index 4f4099d..4fa1420 100644 (file)
@@ -505,7 +505,7 @@ static void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
        if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
                list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) {
                        ipvlan_ht_addr_del(addr, !dev->dismantle);
-                       list_del_rcu(&addr->anode);
+                       list_del(&addr->anode);
                }
        }
        list_del_rcu(&ipvlan->pnode);
@@ -607,7 +607,7 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
 {
        struct ipvl_addr *addr;
 
-       if (ipvlan_addr_busy(ipvlan, ip6_addr, true)) {
+       if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true)) {
                netif_err(ipvlan, ifup, ipvlan->dev,
                          "Failed to add IPv6=%pI6c addr for %s intf\n",
                          ip6_addr, ipvlan->dev->name);
@@ -620,9 +620,13 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
        addr->master = ipvlan;
        memcpy(&addr->ip6addr, ip6_addr, sizeof(struct in6_addr));
        addr->atype = IPVL_IPV6;
-       list_add_tail_rcu(&addr->anode, &ipvlan->addrs);
+       list_add_tail(&addr->anode, &ipvlan->addrs);
        ipvlan->ipv6cnt++;
-       ipvlan_ht_addr_add(ipvlan, addr);
+       /* If the interface is not up, the address will be added to the hash
+        * list by ipvlan_open.
+        */
+       if (netif_running(ipvlan->dev))
+               ipvlan_ht_addr_add(ipvlan, addr);
 
        return 0;
 }
@@ -631,12 +635,12 @@ static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
 {
        struct ipvl_addr *addr;
 
-       addr = ipvlan_ht_addr_lookup(ipvlan->port, ip6_addr, true);
+       addr = ipvlan_find_addr(ipvlan, ip6_addr, true);
        if (!addr)
                return;
 
        ipvlan_ht_addr_del(addr, true);
-       list_del_rcu(&addr->anode);
+       list_del(&addr->anode);
        ipvlan->ipv6cnt--;
        WARN_ON(ipvlan->ipv6cnt < 0);
        kfree_rcu(addr, rcu);
@@ -675,7 +679,7 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
 {
        struct ipvl_addr *addr;
 
-       if (ipvlan_addr_busy(ipvlan, ip4_addr, false)) {
+       if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false)) {
                netif_err(ipvlan, ifup, ipvlan->dev,
                          "Failed to add IPv4=%pI4 on %s intf.\n",
                          ip4_addr, ipvlan->dev->name);
@@ -688,9 +692,13 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
        addr->master = ipvlan;
        memcpy(&addr->ip4addr, ip4_addr, sizeof(struct in_addr));
        addr->atype = IPVL_IPV4;
-       list_add_tail_rcu(&addr->anode, &ipvlan->addrs);
+       list_add_tail(&addr->anode, &ipvlan->addrs);
        ipvlan->ipv4cnt++;
-       ipvlan_ht_addr_add(ipvlan, addr);
+       /* If the interface is not up, the address will be added to the hash
+        * list by ipvlan_open.
+        */
+       if (netif_running(ipvlan->dev))
+               ipvlan_ht_addr_add(ipvlan, addr);
        ipvlan_set_broadcast_mac_filter(ipvlan, true);
 
        return 0;
@@ -700,12 +708,12 @@ static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
 {
        struct ipvl_addr *addr;
 
-       addr = ipvlan_ht_addr_lookup(ipvlan->port, ip4_addr, false);
+       addr = ipvlan_find_addr(ipvlan, ip4_addr, false);
        if (!addr)
                return;
 
        ipvlan_ht_addr_del(addr, true);
-       list_del_rcu(&addr->anode);
+       list_del(&addr->anode);
        ipvlan->ipv4cnt--;
        WARN_ON(ipvlan->ipv4cnt < 0);
        if (!ipvlan->ipv4cnt)
index 5c55f11..75d6f26 100644 (file)
@@ -188,6 +188,8 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
                memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
                skb_put(skb, sizeof(padbytes));
        }
+
+       usbnet_set_skb_tx_stats(skb, 1, 0);
        return skb;
 }
 
index 9311a08..4545e78 100644 (file)
@@ -522,6 +522,7 @@ static const struct driver_info wwan_info = {
 #define DELL_VENDOR_ID         0x413C
 #define REALTEK_VENDOR_ID      0x0bda
 #define SAMSUNG_VENDOR_ID      0x04e8
+#define LENOVO_VENDOR_ID       0x17ef
 
 static const struct usb_device_id      products[] = {
 /* BLACKLIST !!
@@ -702,6 +703,13 @@ static const struct usb_device_id  products[] = {
        .driver_info = 0,
 },
 
+/* Lenovo Thinkpad USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7205, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
 /* WHITELIST!!!
  *
  * CDC Ether uses two interfaces, not necessarily consecutive.
index 80a844e..c3e4da9 100644 (file)
@@ -1172,17 +1172,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
 
        /* return skb */
        ctx->tx_curr_skb = NULL;
-       dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
 
        /* keep private stats: framing overhead and number of NTBs */
        ctx->tx_overhead += skb_out->len - ctx->tx_curr_frame_payload;
        ctx->tx_ntbs++;
 
-       /* usbnet has already counted all the framing overhead.
+       /* usbnet will count all the framing overhead by default.
         * Adjust the stats so that the tx_bytes counter show real
         * payload data instead.
         */
-       dev->net->stats.tx_bytes -= skb_out->len - ctx->tx_curr_frame_payload;
+       usbnet_set_skb_tx_stats(skb_out, n,
+                               ctx->tx_curr_frame_payload - skb_out->len);
 
        return skb_out;
 
index 3eed708..1762ad3 100644 (file)
@@ -46,8 +46,7 @@ enum cx82310_status {
 };
 
 #define CMD_PACKET_SIZE        64
-/* first command after power on can take around 8 seconds */
-#define CMD_TIMEOUT    15000
+#define CMD_TIMEOUT    100
 #define CMD_REPLY_RETRY 5
 
 #define CX82310_MTU    1514
@@ -78,8 +77,9 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
        ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf,
                           CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT);
        if (ret < 0) {
-               dev_err(&dev->udev->dev, "send command %#x: error %d\n",
-                       cmd, ret);
+               if (cmd != CMD_GET_LINK_STATUS)
+                       dev_err(&dev->udev->dev, "send command %#x: error %d\n",
+                               cmd, ret);
                goto end;
        }
 
@@ -90,8 +90,10 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
                                           buf, CMD_PACKET_SIZE, &actual_len,
                                           CMD_TIMEOUT);
                        if (ret < 0) {
-                               dev_err(&dev->udev->dev,
-                                       "reply receive error %d\n", ret);
+                               if (cmd != CMD_GET_LINK_STATUS)
+                                       dev_err(&dev->udev->dev,
+                                               "reply receive error %d\n",
+                                               ret);
                                goto end;
                        }
                        if (actual_len > 0)
@@ -134,6 +136,8 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
        int ret;
        char buf[15];
        struct usb_device *udev = dev->udev;
+       u8 link[3];
+       int timeout = 50;
 
        /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */
        if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0
@@ -160,6 +164,20 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
        if (!dev->partial_data)
                return -ENOMEM;
 
+       /* wait for firmware to become ready (indicated by the link being up) */
+       while (--timeout) {
+               ret = cx82310_cmd(dev, CMD_GET_LINK_STATUS, true, NULL, 0,
+                                 link, sizeof(link));
+               /* the command can time out during boot - it's not an error */
+               if (!ret && link[0] == 1 && link[2] == 1)
+                       break;
+               msleep(500);
+       };
+       if (!timeout) {
+               dev_err(&udev->dev, "firmware not ready in time\n");
+               return -ETIMEDOUT;
+       }
+
        /* enable ethernet mode (?) */
        ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0);
        if (ret) {
@@ -300,9 +318,18 @@ static const struct driver_info    cx82310_info = {
        .tx_fixup       = cx82310_tx_fixup,
 };
 
+#define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+                      USB_DEVICE_ID_MATCH_DEV_INFO, \
+       .idVendor = (vend), \
+       .idProduct = (prod), \
+       .bDeviceClass = (cl), \
+       .bDeviceSubClass = (sc), \
+       .bDeviceProtocol = (pr)
+
 static const struct usb_device_id products[] = {
        {
-               USB_DEVICE_AND_INTERFACE_INFO(0x0572, 0xcb01, 0xff, 0, 0),
+               USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0),
                .driver_info = (unsigned long) &cx82310_info
        },
        { },
index 438fc6b..9f7c0ab 100644 (file)
@@ -492,6 +492,7 @@ enum rtl8152_flags {
 /* Define these values to match your device */
 #define VENDOR_ID_REALTEK              0x0bda
 #define VENDOR_ID_SAMSUNG              0x04e8
+#define VENDOR_ID_LENOVO               0x17ef
 
 #define MCU_TYPE_PLA                   0x0100
 #define MCU_TYPE_USB                   0x0000
@@ -4037,6 +4038,7 @@ static struct usb_device_id rtl8152_table[] = {
        {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)},
        {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)},
        {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
+       {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x7205)},
        {}
 };
 
index b94a0fb..953de13 100644 (file)
@@ -144,6 +144,7 @@ static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
                skb_put(skb, sizeof(padbytes));
        }
 
+       usbnet_set_skb_tx_stats(skb, 1, 0);
        return skb;
 }
 
index 449835f..777757a 100644 (file)
@@ -1188,8 +1188,7 @@ static void tx_complete (struct urb *urb)
        struct usbnet           *dev = entry->dev;
 
        if (urb->status == 0) {
-               if (!(dev->driver_info->flags & FLAG_MULTI_PACKET))
-                       dev->net->stats.tx_packets++;
+               dev->net->stats.tx_packets += entry->packets;
                dev->net->stats.tx_bytes += entry->length;
        } else {
                dev->net->stats.tx_errors++;
@@ -1347,7 +1346,19 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
                } else
                        urb->transfer_flags |= URB_ZERO_PACKET;
        }
-       entry->length = urb->transfer_buffer_length = length;
+       urb->transfer_buffer_length = length;
+
+       if (info->flags & FLAG_MULTI_PACKET) {
+               /* Driver has set number of packets and a length delta.
+                * Calculate the complete length and ensure that it's
+                * positive.
+                */
+               entry->length += length;
+               if (WARN_ON_ONCE(entry->length <= 0))
+                       entry->length = length;
+       } else {
+               usbnet_set_skb_tx_stats(skb, 1, length);
+       }
 
        spin_lock_irqsave(&dev->txq.lock, flags);
        retval = usb_autopm_get_interface_async(dev->intf);
index f1ff366..59b0e97 100644 (file)
@@ -1448,8 +1448,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
 {
        int i;
 
-       for (i = 0; i < vi->max_queue_pairs; i++)
+       for (i = 0; i < vi->max_queue_pairs; i++) {
+               napi_hash_del(&vi->rq[i].napi);
                netif_napi_del(&vi->rq[i].napi);
+       }
 
        kfree(vi->rq);
        kfree(vi->sq);
@@ -1948,11 +1950,8 @@ static int virtnet_freeze(struct virtio_device *vdev)
        cancel_delayed_work_sync(&vi->refill);
 
        if (netif_running(vi->dev)) {
-               for (i = 0; i < vi->max_queue_pairs; i++) {
+               for (i = 0; i < vi->max_queue_pairs; i++)
                        napi_disable(&vi->rq[i].napi);
-                       napi_hash_del(&vi->rq[i].napi);
-                       netif_napi_del(&vi->rq[i].napi);
-               }
        }
 
        remove_vq_common(vi);
index 1e0a775..f8528a4 100644 (file)
@@ -1218,7 +1218,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                        goto drop;
 
                flags &= ~VXLAN_HF_RCO;
-               vni &= VXLAN_VID_MASK;
+               vni &= VXLAN_VNI_MASK;
        }
 
        /* For backwards compatibility, only allow reserved fields to be
@@ -1239,7 +1239,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                flags &= ~VXLAN_GBP_USED_BITS;
        }
 
-       if (flags || (vni & ~VXLAN_VID_MASK)) {
+       if (flags || vni & ~VXLAN_VNI_MASK) {
                /* If there are any unprocessed flags remaining treat
                 * this as a malformed packet. This behavior diverges from
                 * VXLAN RFC (RFC7348) which stipulates that bits in reserved
index cb366ad..f50a6bc 100644 (file)
@@ -219,12 +219,15 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
        struct ath_buf *bf = avp->av_bcbuf;
+       struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
 
        ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
                avp->av_bslot);
 
        tasklet_disable(&sc->bcon_tasklet);
 
+       cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
+
        if (bf && bf->bf_mpdu) {
                struct sk_buff *skb = bf->bf_mpdu;
                dma_unmap_single(sc->dev, bf->bf_buf_addr,
@@ -521,8 +524,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
        }
 
        if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
-               if ((vif->type != NL80211_IFTYPE_AP) ||
-                   (sc->nbcnvifs > 1)) {
+               if (vif->type != NL80211_IFTYPE_AP) {
                        ath_dbg(common, CONFIG,
                                "An AP interface is already present !\n");
                        return false;
@@ -616,12 +618,14 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
         * enabling/disabling SWBA.
         */
        if (changed & BSS_CHANGED_BEACON_ENABLED) {
-               if (!bss_conf->enable_beacon &&
-                   (sc->nbcnvifs <= 1)) {
-                       cur_conf->enable_beacon = false;
-               } else if (bss_conf->enable_beacon) {
-                       cur_conf->enable_beacon = true;
-                       ath9k_cache_beacon_config(sc, ctx, bss_conf);
+               bool enabled = cur_conf->enable_beacon;
+
+               if (!bss_conf->enable_beacon) {
+                       cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
+               } else {
+                       cur_conf->enable_beacon |= BIT(avp->av_bslot);
+                       if (!enabled)
+                               ath9k_cache_beacon_config(sc, ctx, bss_conf);
                }
        }
 
index 2b79a56..d237373 100644 (file)
@@ -54,7 +54,7 @@ struct ath_beacon_config {
        u16 dtim_period;
        u16 bmiss_timeout;
        u8 dtim_count;
-       bool enable_beacon;
+       u8 enable_beacon;
        bool ibss_creator;
        u32 nexttbtt;
        u32 intval;
index 60aa8d7..8529014 100644 (file)
@@ -424,7 +424,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
        ah->power_mode = ATH9K_PM_UNDEFINED;
        ah->htc_reset_init = true;
 
-       ah->tpc_enabled = true;
+       ah->tpc_enabled = false;
 
        ah->ani_function = ATH9K_ANI_ALL;
        if (!AR_SREV_9300_20_OR_LATER(ah))
index ccbdb05..75345c1 100644 (file)
@@ -5370,6 +5370,7 @@ static void b43_supported_bands(struct b43_wldev *dev, bool *have_2ghz_phy,
        case 0x432a: /* BCM4321 */
        case 0x432d: /* BCM4322 */
        case 0x4352: /* BCM43222 */
+       case 0x435a: /* BCM43228 */
        case 0x4333: /* BCM4331 */
        case 0x43a2: /* BCM4360 */
        case 0x43b3: /* BCM4352 */
index defb7a4..7748a1c 100644 (file)
@@ -126,7 +126,8 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
        brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
        if (drvr->bus_if->wowl_supported)
                brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
-       brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
+       if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
+               brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
 
        /* set chip related quirks */
        switch (drvr->bus_if->chip) {
index 50cdf70..8eff275 100644 (file)
@@ -39,13 +39,22 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
        void *dcmd_buf = NULL, *wr_pointer;
        u16 msglen, maxmsglen = PAGE_SIZE - 0x100;
 
-       brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set,
-                 cmdhdr->len);
+       if (len < sizeof(*cmdhdr)) {
+               brcmf_err("vendor command too short: %d\n", len);
+               return -EINVAL;
+       }
 
        vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
        ifp = vif->ifp;
 
-       len -= sizeof(struct brcmf_vndr_dcmd_hdr);
+       brcmf_dbg(TRACE, "ifidx=%d, cmd=%d\n", ifp->ifidx, cmdhdr->cmd);
+
+       if (cmdhdr->offset > len) {
+               brcmf_err("bad buffer offset %d > %d\n", cmdhdr->offset, len);
+               return -EINVAL;
+       }
+
+       len -= cmdhdr->offset;
        ret_len = cmdhdr->len;
        if (ret_len > 0 || len > 0) {
                if (len > BRCMF_DCMD_MAXLEN) {
index a6f22c3..3811878 100644 (file)
@@ -708,7 +708,6 @@ struct iwl_priv {
        unsigned long reload_jiffies;
        int reload_count;
        bool ucode_loaded;
-       bool init_ucode_run;            /* Don't run init uCode again */
 
        u8 plcp_delta_threshold;
 
index 47e64e8..cceb026 100644 (file)
@@ -1114,16 +1114,17 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) |
                        BIT(IWL_DEFAULT_CMD_QUEUE_NUM));
 
-       if (vif)
-               scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]);
-
-       IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues);
-       if (iwlagn_txfifo_flush(priv, scd_queues)) {
-               IWL_ERR(priv, "flush request fail\n");
-               goto done;
+       if (drop) {
+               IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n",
+                                   scd_queues);
+               if (iwlagn_txfifo_flush(priv, scd_queues)) {
+                       IWL_ERR(priv, "flush request fail\n");
+                       goto done;
+               }
        }
+
        IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n");
-       iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
+       iwl_trans_wait_tx_queue_empty(priv->trans, scd_queues);
 done:
        mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
index 4dbef7e..5244e43 100644 (file)
@@ -418,9 +418,6 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
        if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len)
                return 0;
 
-       if (priv->init_ucode_run)
-               return 0;
-
        iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
                                   calib_complete, ARRAY_SIZE(calib_complete),
                                   iwlagn_wait_calib, priv);
@@ -440,8 +437,6 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
         */
        ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
                                        UCODE_CALIB_TIMEOUT);
-       if (!ret)
-               priv->init_ucode_run = true;
 
        goto out;
 
index c3817fa..06f6cc0 100644 (file)
@@ -95,7 +95,8 @@ static const struct iwl_eeprom_params iwl1000_eeprom_params = {
        .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION,  \
        .base_params = &iwl1000_base_params,                    \
        .eeprom_params = &iwl1000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl1000_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
@@ -121,7 +122,8 @@ const struct iwl_cfg iwl1000_bg_cfg = {
        .base_params = &iwl1000_base_params,                    \
        .eeprom_params = &iwl1000_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl100_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
index 21e5d08..890b95f 100644 (file)
@@ -123,7 +123,9 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
        .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,          \
        .base_params = &iwl2000_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
+
 
 const struct iwl_cfg iwl2000_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
@@ -149,7 +151,8 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
        .base_params = &iwl2030_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl2030_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
@@ -170,7 +173,8 @@ const struct iwl_cfg iwl2030_2bgn_cfg = {
        .base_params = &iwl2000_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl105_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
@@ -197,7 +201,8 @@ const struct iwl_cfg iwl105_bgn_d_cfg = {
        .base_params = &iwl2030_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl135_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
index 332bbed..724194e 100644 (file)
@@ -93,7 +93,8 @@ static const struct iwl_eeprom_params iwl5000_eeprom_params = {
        .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION,  \
        .base_params = &iwl5000_base_params,                    \
        .eeprom_params = &iwl5000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl5300_agn_cfg = {
        .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
@@ -158,7 +159,8 @@ const struct iwl_cfg iwl5350_agn_cfg = {
        .base_params = &iwl5000_base_params,                    \
        .eeprom_params = &iwl5000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl5150_agn_cfg = {
        .name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
index 8f2c3c8..21b2630 100644 (file)
@@ -145,7 +145,8 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = {
        .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6005_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
@@ -199,7 +200,8 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
        .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6030_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
@@ -235,7 +237,8 @@ const struct iwl_cfg iwl6030_2bg_cfg = {
        .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6035_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
@@ -290,7 +293,8 @@ const struct iwl_cfg iwl130_bg_cfg = {
        .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION,  \
        .base_params = &iwl6000_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6000i_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
@@ -322,7 +326,8 @@ const struct iwl_cfg iwl6000i_2bg_cfg = {
        .base_params = &iwl6050_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6050_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
@@ -347,7 +352,8 @@ const struct iwl_cfg iwl6050_2abg_cfg = {
        .base_params = &iwl6050_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6150_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
index 996e7f1..c7154ac 100644 (file)
@@ -1257,6 +1257,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
                                op->name, err);
 #endif
        }
+       kfree(pieces);
        return;
 
  try_again:
index 1ec4d55..7810c41 100644 (file)
@@ -793,7 +793,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
-       if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
+       if (mvmvif->phy_ctxt &&
+           IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
                               mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
index d530ef3..542ee74 100644 (file)
@@ -832,7 +832,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
-       if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
+       if (mvmvif->phy_ctxt &&
+           data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
        IWL_DEBUG_COEX(data->mvm,
index 1ff7ec0..09654e7 100644 (file)
@@ -405,7 +405,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
                        &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
 
-               if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER)
+               if ((mvm->fw->ucode_capa.capa[0] &
+                    IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
+                   (mvm->fw->ucode_capa.api[0] &
+                    IWL_UCODE_TLV_API_LQ_SS_PARAMS))
                        hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |=
                                IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
        }
@@ -2215,7 +2218,19 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
 
        mutex_lock(&mvm->mutex);
 
-       iwl_mvm_cancel_scan(mvm);
+       /* Due to a race condition, it's possible that mac80211 asks
+        * us to stop a hw_scan when it's already stopped.  This can
+        * happen, for instance, if we stopped the scan ourselves,
+        * called ieee80211_scan_completed() and the userspace called
+        * cancel scan scan before ieee80211_scan_work() could run.
+        * To handle that, simply return if the scan is not running.
+       */
+       /* FIXME: for now, we ignore this race for UMAC scans, since
+        * they don't set the scan_status.
+        */
+       if ((mvm->scan_status == IWL_MVM_SCAN_OS) ||
+           (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+               iwl_mvm_cancel_scan(mvm);
 
        mutex_unlock(&mvm->mutex);
 }
@@ -2559,12 +2574,29 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
        int ret;
 
        mutex_lock(&mvm->mutex);
+
+       /* Due to a race condition, it's possible that mac80211 asks
+        * us to stop a sched_scan when it's already stopped.  This
+        * can happen, for instance, if we stopped the scan ourselves,
+        * called ieee80211_sched_scan_stopped() and the userspace called
+        * stop sched scan scan before ieee80211_sched_scan_stopped_work()
+        * could run.  To handle this, simply return if the scan is
+        * not running.
+       */
+       /* FIXME: for now, we ignore this race for UMAC scans, since
+        * they don't set the scan_status.
+        */
+       if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
+           !(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+               mutex_unlock(&mvm->mutex);
+               return 0;
+       }
+
        ret = iwl_mvm_scan_offload_stop(mvm, false);
        mutex_unlock(&mvm->mutex);
        iwl_mvm_wait_for_async_handlers(mvm);
 
        return ret;
-
 }
 
 static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
index 194bd1f..078f24c 100644 (file)
@@ -134,9 +134,12 @@ enum rs_column_mode {
 #define MAX_NEXT_COLUMNS 7
 #define MAX_COLUMN_CHECKS 3
 
+struct rs_tx_column;
+
 typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm,
                                     struct ieee80211_sta *sta,
-                                    struct iwl_scale_tbl_info *tbl);
+                                    struct iwl_scale_tbl_info *tbl,
+                                    const struct rs_tx_column *next_col);
 
 struct rs_tx_column {
        enum rs_column_mode mode;
@@ -147,13 +150,15 @@ struct rs_tx_column {
 };
 
 static bool rs_ant_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                        struct iwl_scale_tbl_info *tbl)
+                        struct iwl_scale_tbl_info *tbl,
+                        const struct rs_tx_column *next_col)
 {
-       return iwl_mvm_bt_coex_is_ant_avail(mvm, tbl->rate.ant);
+       return iwl_mvm_bt_coex_is_ant_avail(mvm, next_col->ant);
 }
 
 static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                         struct iwl_scale_tbl_info *tbl)
+                         struct iwl_scale_tbl_info *tbl,
+                         const struct rs_tx_column *next_col)
 {
        if (!sta->ht_cap.ht_supported)
                return false;
@@ -171,7 +176,8 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 }
 
 static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                         struct iwl_scale_tbl_info *tbl)
+                         struct iwl_scale_tbl_info *tbl,
+                         const struct rs_tx_column *next_col)
 {
        if (!sta->ht_cap.ht_supported)
                return false;
@@ -180,7 +186,8 @@ static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 }
 
 static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                        struct iwl_scale_tbl_info *tbl)
+                        struct iwl_scale_tbl_info *tbl,
+                        const struct rs_tx_column *next_col)
 {
        struct rs_rate *rate = &tbl->rate;
        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
@@ -1271,6 +1278,9 @@ static void rs_mac80211_tx_status(void *mvm_r,
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
+       if (!iwl_mvm_sta_from_mac80211(sta)->vif)
+               return;
+
        if (!ieee80211_is_data(hdr->frame_control) ||
            info->flags & IEEE80211_TX_CTL_NO_ACK)
                return;
@@ -1590,7 +1600,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
 
                for (j = 0; j < MAX_COLUMN_CHECKS; j++) {
                        allow_func = next_col->checks[j];
-                       if (allow_func && !allow_func(mvm, sta, tbl))
+                       if (allow_func && !allow_func(mvm, sta, tbl, next_col))
                                break;
                }
 
@@ -2504,6 +2514,14 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl_lq_sta *lq_sta = mvm_sta;
 
+       if (sta && !iwl_mvm_sta_from_mac80211(sta)->vif) {
+               /* if vif isn't initialized mvm doesn't know about
+                * this station, so don't do anything with the it
+                */
+               sta = NULL;
+               mvm_sta = NULL;
+       }
+
        /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
 
        /* Treat uninitialized rate scaling data same as non-existing. */
@@ -2820,6 +2838,9 @@ static void rs_rate_update(void *mvm_r,
                        (struct iwl_op_mode *)mvm_r;
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
 
+       if (!iwl_mvm_sta_from_mac80211(sta)->vif)
+               return;
+
        /* Stop any ongoing aggregations as rs starts off assuming no agg */
        for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
                ieee80211_stop_tx_ba_session(sta, tid);
@@ -3580,9 +3601,15 @@ static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf,
 
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(ss_force, 32);
 
-static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
+static void rs_add_debugfs(void *mvm, void *priv_sta, struct dentry *dir)
 {
-       struct iwl_lq_sta *lq_sta = mvm_sta;
+       struct iwl_lq_sta *lq_sta = priv_sta;
+       struct iwl_mvm_sta *mvmsta;
+
+       mvmsta = container_of(lq_sta, struct iwl_mvm_sta, lq_sta);
+
+       if (!mvmsta->vif)
+               return;
 
        debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
                            lq_sta, &rs_sta_dbgfs_scale_table_ops);
index 7e9aa3c..c47c805 100644 (file)
@@ -1128,8 +1128,10 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        if (mvm->scan_status == IWL_MVM_SCAN_NONE)
                return 0;
 
-       if (iwl_mvm_is_radio_killed(mvm))
+       if (iwl_mvm_is_radio_killed(mvm)) {
+               ret = 0;
                goto out;
+       }
 
        if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
            (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
@@ -1148,16 +1150,14 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
                IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n",
                               sched ? "offloaded " : "", ret);
                iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
-               return ret;
+               goto out;
        }
 
        IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
                       sched ? "offloaded " : "");
 
        ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
-       if (ret)
-               return ret;
-
+out:
        /*
         * Clear the scan status so the next scan requests will succeed. This
         * also ensures the Rx handler doesn't do anything, as the scan was
@@ -1167,7 +1167,6 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        if (mvm->scan_status == IWL_MVM_SCAN_OS)
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
 
-out:
        mvm->scan_status = IWL_MVM_SCAN_NONE;
 
        if (notify) {
@@ -1177,7 +1176,7 @@ out:
                        ieee80211_scan_completed(mvm->hw, true);
        }
 
-       return 0;
+       return ret;
 }
 
 static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm,
index 54fafbf..4b81c0b 100644 (file)
@@ -197,6 +197,8 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm,
                             struct iwl_time_event_notif *notif)
 {
        if (!le32_to_cpu(notif->status)) {
+               if (te_data->vif->type == NL80211_IFTYPE_STATION)
+                       ieee80211_connection_loss(te_data->vif);
                IWL_DEBUG_TE(mvm, "CSA time event failed to start\n");
                iwl_mvm_te_clear_data(mvm, te_data);
                return;
@@ -750,8 +752,7 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
         * request
         */
        list_for_each_entry(te_data, &mvm->time_event_list, list) {
-               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE &&
-                   te_data->running) {
+               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
                        mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
                        is_p2p = true;
                        goto remove_te;
@@ -766,10 +767,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
         * request
         */
        list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {
-               if (te_data->running) {
-                       mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
-                       goto remove_te;
-               }
+               mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+               goto remove_te;
        }
 
 remove_te:
index 07304e1..96a0540 100644 (file)
@@ -949,8 +949,10 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        mvmsta = iwl_mvm_sta_from_mac80211(sta);
        tid_data = &mvmsta->tid_data[tid];
 
-       if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d",
-                     tid_data->txq_id, tid, scd_flow)) {
+       if (tid_data->txq_id != scd_flow) {
+               IWL_ERR(mvm,
+                       "invalid BA notification: Q %d, tid %d, flow %d\n",
+                       tid_data->txq_id, tid, scd_flow);
                rcu_read_unlock();
                return 0;
        }
index dbd6bcf..686dd30 100644 (file)
@@ -368,10 +368,12 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
 /* 3165 Series */
        {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3166, 0x4310, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3166, 0x4210, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x8010, iwl3165_2ac_cfg)},
 
 /* 7265 Series */
        {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
index 1d46774..074f716 100644 (file)
@@ -1386,8 +1386,11 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
                }
 
                return true;
-       } else if (0x86DD == ether_type) {
-               return true;
+       } else if (ETH_P_IPV6 == ether_type) {
+               /* TODO: Handle any IPv6 cases that need special handling.
+                * For now, always return false
+                */
+               goto end;
        }
 
 end:
index a62170e..8c45cf4 100644 (file)
@@ -1124,12 +1124,22 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        /*This is for new trx flow*/
        struct rtl_tx_buffer_desc *pbuffer_desc = NULL;
        u8 temp_one = 1;
+       u8 *entry;
 
        memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
        ring = &rtlpci->tx_ring[BEACON_QUEUE];
        pskb = __skb_dequeue(&ring->queue);
-       if (pskb)
+       if (rtlpriv->use_new_trx_flow)
+               entry = (u8 *)(&ring->buffer_desc[ring->idx]);
+       else
+               entry = (u8 *)(&ring->desc[ring->idx]);
+       if (pskb) {
+               pci_unmap_single(rtlpci->pdev,
+                                rtlpriv->cfg->ops->get_desc(
+                                (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
+                                pskb->len, PCI_DMA_TODEVICE);
                kfree_skb(pskb);
+       }
 
        /*NB: the beacon data buffer must be 32-bit aligned. */
        pskb = ieee80211_beacon_get(hw, mac->vif);
index cab9f52..997cf09 100644 (file)
@@ -96,6 +96,7 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
 static void make_tx_response(struct xenvif_queue *queue,
                             struct xen_netif_tx_request *txp,
                             s8       st);
+static void push_tx_responses(struct xenvif_queue *queue);
 
 static inline int tx_work_todo(struct xenvif_queue *queue);
 
@@ -655,15 +656,10 @@ static void xenvif_tx_err(struct xenvif_queue *queue,
        unsigned long flags;
 
        do {
-               int notify;
-
                spin_lock_irqsave(&queue->response_lock, flags);
                make_tx_response(queue, txp, XEN_NETIF_RSP_ERROR);
-               RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
+               push_tx_responses(queue);
                spin_unlock_irqrestore(&queue->response_lock, flags);
-               if (notify)
-                       notify_remote_via_irq(queue->tx_irq);
-
                if (cons == end)
                        break;
                txp = RING_GET_REQUEST(&queue->tx, cons++);
@@ -1657,7 +1653,6 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
 {
        struct pending_tx_info *pending_tx_info;
        pending_ring_idx_t index;
-       int notify;
        unsigned long flags;
 
        pending_tx_info = &queue->pending_tx_info[pending_idx];
@@ -1673,12 +1668,9 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
        index = pending_index(queue->pending_prod++);
        queue->pending_ring[index] = pending_idx;
 
-       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
+       push_tx_responses(queue);
 
        spin_unlock_irqrestore(&queue->response_lock, flags);
-
-       if (notify)
-               notify_remote_via_irq(queue->tx_irq);
 }
 
 
@@ -1699,6 +1691,15 @@ static void make_tx_response(struct xenvif_queue *queue,
        queue->tx.rsp_prod_pvt = ++i;
 }
 
+static void push_tx_responses(struct xenvif_queue *queue)
+{
+       int notify;
+
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
+       if (notify)
+               notify_remote_via_irq(queue->tx_irq);
+}
+
 static struct xen_netif_rx_response *make_rx_response(struct xenvif_queue *queue,
                                             u16      id,
                                             s8       st,
index e9b960f..720aaf6 100644 (file)
@@ -1008,8 +1008,7 @@ err:
 
 static int xennet_change_mtu(struct net_device *dev, int mtu)
 {
-       int max = xennet_can_sg(dev) ?
-               XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER : ETH_DATA_LEN;
+       int max = xennet_can_sg(dev) ? XEN_NETIF_MAX_TX_SIZE : ETH_DATA_LEN;
 
        if (mtu > max)
                return -EINVAL;
@@ -1279,8 +1278,6 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
        netdev->ethtool_ops = &xennet_ethtool_ops;
        SET_NETDEV_DEV(netdev, &dev->dev);
 
-       netif_set_gso_max_size(netdev, XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER);
-
        np->netdev = netdev;
 
        netif_carrier_off(netdev);
index 7563f36..fcacb18 100644 (file)
@@ -6,8 +6,7 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o
 obj-$(CONFIG_OF_ADDRESS)  += address.o
 obj-$(CONFIG_OF_IRQ)    += irq.o
 obj-$(CONFIG_OF_NET)   += of_net.o
-obj-$(CONFIG_OF_UNITTEST) += of_unittest.o
-of_unittest-objs := unittest.o unittest-data/testcases.dtb.o
+obj-$(CONFIG_OF_UNITTEST) += unittest.o
 obj-$(CONFIG_OF_MDIO)  += of_mdio.o
 obj-$(CONFIG_OF_PCI)   += of_pci.o
 obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
@@ -16,5 +15,7 @@ obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
 obj-$(CONFIG_OF_RESOLVE)  += resolver.o
 obj-$(CONFIG_OF_OVERLAY) += overlay.o
 
+obj-$(CONFIG_OF_UNITTEST) += unittest-data/
+
 CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt
 CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt
index ad29069..78a7dcb 100644 (file)
@@ -450,12 +450,17 @@ static struct of_bus *of_match_bus(struct device_node *np)
        return NULL;
 }
 
-static int of_empty_ranges_quirk(void)
+static int of_empty_ranges_quirk(struct device_node *np)
 {
        if (IS_ENABLED(CONFIG_PPC)) {
-               /* To save cycles, we cache the result */
+               /* To save cycles, we cache the result for global "Mac" setting */
                static int quirk_state = -1;
 
+               /* PA-SEMI sdc DT bug */
+               if (of_device_is_compatible(np, "1682m-sdc"))
+                       return true;
+
+               /* Make quirk cached */
                if (quirk_state < 0)
                        quirk_state =
                                of_machine_is_compatible("Power Macintosh") ||
@@ -490,7 +495,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
         * This code is only enabled on powerpc. --gcl
         */
        ranges = of_get_property(parent, rprop, &rlen);
-       if (ranges == NULL && !of_empty_ranges_quirk()) {
+       if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
                pr_debug("OF: no ranges; cannot translate\n");
                return 1;
        }
index adb8764..69566b6 100644 (file)
@@ -715,13 +715,8 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent,
 {
        struct device_node *child;
        int len;
-       const char *end;
 
-       end = strchr(path, ':');
-       if (!end)
-               end = strchrnul(path, '/');
-
-       len = end - path;
+       len = strcspn(path, "/:");
        if (!len)
                return NULL;
 
@@ -1893,10 +1888,8 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
                        name = of_get_property(of_chosen, "linux,stdout-path", NULL);
                if (IS_ENABLED(CONFIG_PPC) && !name)
                        name = of_get_property(of_aliases, "stdout", NULL);
-               if (name) {
+               if (name)
                        of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
-                       add_preferred_console("stdout-path", 0, NULL);
-               }
        }
 
        if (!of_aliases)
@@ -2090,13 +2083,44 @@ int of_graph_parse_endpoint(const struct device_node *node,
 EXPORT_SYMBOL(of_graph_parse_endpoint);
 
 /**
+ * of_graph_get_port_by_id() - get the port matching a given id
+ * @parent: pointer to the parent device node
+ * @id: id of the port
+ *
+ * Return: A 'port' node pointer with refcount incremented. The caller
+ * has to use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
+{
+       struct device_node *node, *port;
+
+       node = of_get_child_by_name(parent, "ports");
+       if (node)
+               parent = node;
+
+       for_each_child_of_node(parent, port) {
+               u32 port_id = 0;
+
+               if (of_node_cmp(port->name, "port") != 0)
+                       continue;
+               of_property_read_u32(port, "reg", &port_id);
+               if (id == port_id)
+                       break;
+       }
+
+       of_node_put(node);
+
+       return port;
+}
+EXPORT_SYMBOL(of_graph_get_port_by_id);
+
+/**
  * of_graph_get_next_endpoint() - get next endpoint node
  * @parent: pointer to the parent device node
  * @prev: previous endpoint node, or NULL to get first
  *
  * Return: An 'endpoint' node pointer with refcount incremented. Refcount
- * of the passed @prev node is not decremented, the caller have to use
- * of_node_put() on it when done.
+ * of the passed @prev node is decremented.
  */
 struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
                                        struct device_node *prev)
@@ -2132,12 +2156,6 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
                if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
                              __func__, prev->full_name))
                        return NULL;
-
-               /*
-                * Avoid dropping prev node refcount to 0 when getting the next
-                * child below.
-                */
-               of_node_get(prev);
        }
 
        while (1) {
index 0d77658..1a79806 100644 (file)
@@ -290,7 +290,7 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
        struct device_node *p;
        const __be32 *intspec, *tmp, *addr;
        u32 intsize, intlen;
-       int i, res = -EINVAL;
+       int i, res;
 
        pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
 
@@ -323,15 +323,19 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
 
        /* Get size of interrupt specifier */
        tmp = of_get_property(p, "#interrupt-cells", NULL);
-       if (tmp == NULL)
+       if (tmp == NULL) {
+               res = -EINVAL;
                goto out;
+       }
        intsize = be32_to_cpu(*tmp);
 
        pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
 
        /* Check index */
-       if ((index + 1) * intsize > intlen)
+       if ((index + 1) * intsize > intlen) {
+               res = -EINVAL;
                goto out;
+       }
 
        /* Copy intspec into irq structure */
        intspec += index * intsize;
diff --git a/drivers/of/unittest-data/.gitignore b/drivers/of/unittest-data/.gitignore
new file mode 100644 (file)
index 0000000..4b3cf8b
--- /dev/null
@@ -0,0 +1,2 @@
+testcases.dtb
+testcases.dtb.S
diff --git a/drivers/of/unittest-data/Makefile b/drivers/of/unittest-data/Makefile
new file mode 100644 (file)
index 0000000..1ac5cc0
--- /dev/null
@@ -0,0 +1,7 @@
+obj-y += testcases.dtb.o
+
+targets += testcases.dtb testcases.dtb.S
+
+.SECONDARY: \
+       $(obj)/testcases.dtb.S \
+       $(obj)/testcases.dtb
index 244226c..02ba56c 100644 (file)
@@ -4,94 +4,94 @@
                overlay-node {
 
                        /* test bus */
-                       selftestbus: test-bus {
+                       unittestbus: test-bus {
                                compatible = "simple-bus";
                                #address-cells = <1>;
                                #size-cells = <0>;
 
-                               selftest100: test-selftest100 {
-                                       compatible = "selftest";
+                               unittest100: test-unittest100 {
+                                       compatible = "unittest";
                                        status = "okay";
                                        reg = <100>;
                                };
 
-                               selftest101: test-selftest101 {
-                                       compatible = "selftest";
+                               unittest101: test-unittest101 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <101>;
                                };
 
-                               selftest0: test-selftest0 {
-                                       compatible = "selftest";
+                               unittest0: test-unittest0 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <0>;
                                };
 
-                               selftest1: test-selftest1 {
-                                       compatible = "selftest";
+                               unittest1: test-unittest1 {
+                                       compatible = "unittest";
                                        status = "okay";
                                        reg = <1>;
                                };
 
-                               selftest2: test-selftest2 {
-                                       compatible = "selftest";
+                               unittest2: test-unittest2 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <2>;
                                };
 
-                               selftest3: test-selftest3 {
-                                       compatible = "selftest";
+                               unittest3: test-unittest3 {
+                                       compatible = "unittest";
                                        status = "okay";
                                        reg = <3>;
                                };
 
-                               selftest5: test-selftest5 {
-                                       compatible = "selftest";
+                               unittest5: test-unittest5 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <5>;
                                };
 
-                               selftest6: test-selftest6 {
-                                       compatible = "selftest";
+                               unittest6: test-unittest6 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <6>;
                                };
 
-                               selftest7: test-selftest7 {
-                                       compatible = "selftest";
+                               unittest7: test-unittest7 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <7>;
                                };
 
-                               selftest8: test-selftest8 {
-                                       compatible = "selftest";
+                               unittest8: test-unittest8 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <8>;
                                };
 
                                i2c-test-bus {
-                                       compatible = "selftest-i2c-bus";
+                                       compatible = "unittest-i2c-bus";
                                        status = "okay";
                                        reg = <50>;
 
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       test-selftest12 {
+                                       test-unittest12 {
                                                reg = <8>;
-                                               compatible = "selftest-i2c-dev";
+                                               compatible = "unittest-i2c-dev";
                                                status = "disabled";
                                        };
 
-                                       test-selftest13 {
+                                       test-unittest13 {
                                                reg = <9>;
-                                               compatible = "selftest-i2c-dev";
+                                               compatible = "unittest-i2c-dev";
                                                status = "okay";
                                        };
 
-                                       test-selftest14 {
+                                       test-unittest14 {
                                                reg = <10>;
-                                               compatible = "selftest-i2c-mux";
+                                               compatible = "unittest-i2c-mux";
                                                status = "okay";
 
                                                #address-cells = <1>;
 
                                                        test-mux-dev {
                                                                reg = <32>;
-                                                               compatible = "selftest-i2c-dev";
+                                                               compatible = "unittest-i2c-dev";
                                                                status = "okay";
                                                        };
                                                };
                /* test enable using absolute target path */
                overlay0 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest0";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest0";
                                __overlay__ {
                                        status = "okay";
                                };
                /* test disable using absolute target path */
                overlay1 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest1";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest1";
                                __overlay__ {
                                        status = "disabled";
                                };
                /* test enable using label */
                overlay2 {
                        fragment@0 {
-                               target = <&selftest2>;
+                               target = <&unittest2>;
                                __overlay__ {
                                        status = "okay";
                                };
                /* test disable using label */
                overlay3 {
                        fragment@0 {
-                               target = <&selftest3>;
+                               target = <&unittest3>;
                                __overlay__ {
                                        status = "disabled";
                                };
                /* test insertion of a full node */
                overlay4 {
                        fragment@0 {
-                               target = <&selftestbus>;
+                               target = <&unittestbus>;
                                __overlay__ {
 
                                        /* suppress DTC warning */
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       test-selftest4 {
-                                               compatible = "selftest";
+                                       test-unittest4 {
+                                               compatible = "unittest";
                                                status = "okay";
                                                reg = <4>;
                                        };
                /* test overlay apply revert */
                overlay5 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest5";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest5";
                                __overlay__ {
                                        status = "okay";
                                };
                /* test overlays application and removal in sequence */
                overlay6 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest6";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest6";
                                __overlay__ {
                                        status = "okay";
                                };
                };
                overlay7 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest7";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest7";
                                __overlay__ {
                                        status = "okay";
                                };
                /* test overlays application and removal in bad sequence */
                overlay8 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest8";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest8";
                                __overlay__ {
                                        status = "okay";
                                };
                };
                overlay9 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest8";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest8";
                                __overlay__ {
                                        property-foo = "bar";
                                };
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       test-selftest10 {
-                                               compatible = "selftest";
+                                       test-unittest10 {
+                                               compatible = "unittest";
                                                status = "okay";
                                                reg = <10>;
 
                                                #address-cells = <1>;
                                                #size-cells = <0>;
 
-                                               test-selftest101 {
-                                                       compatible = "selftest";
+                                               test-unittest101 {
+                                                       compatible = "unittest";
                                                        status = "okay";
                                                        reg = <1>;
                                                };
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       test-selftest11 {
-                                               compatible = "selftest";
+                                       test-unittest11 {
+                                               compatible = "unittest";
                                                status = "okay";
                                                reg = <11>;
 
                                                #address-cells = <1>;
                                                #size-cells = <0>;
 
-                                               test-selftest111 {
-                                                       compatible = "selftest";
+                                               test-unittest111 {
+                                                       compatible = "unittest";
                                                        status = "okay";
                                                        reg = <1>;
                                                };
                /* test enable using absolute target path (i2c) */
                overlay12 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-selftest12";
+                               target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12";
                                __overlay__ {
                                        status = "okay";
                                };
                /* test disable using absolute target path (i2c) */
                overlay13 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-selftest13";
+                               target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13";
                                __overlay__ {
                                        status = "disabled";
                                };
                                __overlay__ {
                                        #address-cells = <1>;
                                        #size-cells = <0>;
-                                       test-selftest15 {
+                                       test-unittest15 {
                                                reg = <11>;
-                                               compatible = "selftest-i2c-mux";
+                                               compatible = "unittest-i2c-mux";
                                                status = "okay";
 
                                                #address-cells = <1>;
 
                                                        test-mux-dev {
                                                                reg = <32>;
-                                                               compatible = "selftest-i2c-dev";
+                                                               compatible = "unittest-i2c-dev";
                                                                status = "okay";
                                                        };
                                                };
index aba8946..fdb5977 100644 (file)
 
 #include "of_private.h"
 
-static struct selftest_results {
+static struct unittest_results {
        int passed;
        int failed;
-} selftest_results;
+} unittest_results;
 
-#define selftest(result, fmt, ...) ({ \
+#define unittest(result, fmt, ...) ({ \
        bool failed = !(result); \
        if (failed) { \
-               selftest_results.failed++; \
+               unittest_results.failed++; \
                pr_err("FAIL %s():%i " fmt, __func__, __LINE__, ##__VA_ARGS__); \
        } else { \
-               selftest_results.passed++; \
+               unittest_results.passed++; \
                pr_debug("pass %s():%i\n", __func__, __LINE__); \
        } \
        failed; \
 })
 
-static void __init of_selftest_find_node_by_name(void)
+static void __init of_unittest_find_node_by_name(void)
 {
        struct device_node *np;
        const char *options;
 
        np = of_find_node_by_path("/testcase-data");
-       selftest(np && !strcmp("/testcase-data", np->full_name),
+       unittest(np && !strcmp("/testcase-data", np->full_name),
                "find /testcase-data failed\n");
        of_node_put(np);
 
        /* Test if trailing '/' works */
        np = of_find_node_by_path("/testcase-data/");
-       selftest(!np, "trailing '/' on /testcase-data/ should fail\n");
+       unittest(!np, "trailing '/' on /testcase-data/ should fail\n");
 
        np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
-       selftest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
+       unittest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
                "find /testcase-data/phandle-tests/consumer-a failed\n");
        of_node_put(np);
 
        np = of_find_node_by_path("testcase-alias");
-       selftest(np && !strcmp("/testcase-data", np->full_name),
+       unittest(np && !strcmp("/testcase-data", np->full_name),
                "find testcase-alias failed\n");
        of_node_put(np);
 
        /* Test if trailing '/' works on aliases */
        np = of_find_node_by_path("testcase-alias/");
-       selftest(!np, "trailing '/' on testcase-alias/ should fail\n");
+       unittest(!np, "trailing '/' on testcase-alias/ should fail\n");
 
        np = of_find_node_by_path("testcase-alias/phandle-tests/consumer-a");
-       selftest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
+       unittest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
                "find testcase-alias/phandle-tests/consumer-a failed\n");
        of_node_put(np);
 
        np = of_find_node_by_path("/testcase-data/missing-path");
-       selftest(!np, "non-existent path returned node %s\n", np->full_name);
+       unittest(!np, "non-existent path returned node %s\n", np->full_name);
        of_node_put(np);
 
        np = of_find_node_by_path("missing-alias");
-       selftest(!np, "non-existent alias returned node %s\n", np->full_name);
+       unittest(!np, "non-existent alias returned node %s\n", np->full_name);
        of_node_put(np);
 
        np = of_find_node_by_path("testcase-alias/missing-path");
-       selftest(!np, "non-existent alias with relative path returned node %s\n", np->full_name);
+       unittest(!np, "non-existent alias with relative path returned node %s\n", np->full_name);
        of_node_put(np);
 
        np = of_find_node_opts_by_path("/testcase-data:testoption", &options);
-       selftest(np && !strcmp("testoption", options),
+       unittest(np && !strcmp("testoption", options),
                 "option path test failed\n");
        of_node_put(np);
 
        np = of_find_node_opts_by_path("/testcase-data:test/option", &options);
-       selftest(np && !strcmp("test/option", options),
+       unittest(np && !strcmp("test/option", options),
                 "option path test, subcase #1 failed\n");
        of_node_put(np);
 
+       np = of_find_node_opts_by_path("/testcase-data/testcase-device1:test/option", &options);
+       unittest(np && !strcmp("test/option", options),
+                "option path test, subcase #2 failed\n");
+       of_node_put(np);
+
        np = of_find_node_opts_by_path("/testcase-data:testoption", NULL);
-       selftest(np, "NULL option path test failed\n");
+       unittest(np, "NULL option path test failed\n");
        of_node_put(np);
 
        np = of_find_node_opts_by_path("testcase-alias:testaliasoption",
                                       &options);
-       selftest(np && !strcmp("testaliasoption", options),
+       unittest(np && !strcmp("testaliasoption", options),
                 "option alias path test failed\n");
        of_node_put(np);
 
        np = of_find_node_opts_by_path("testcase-alias:test/alias/option",
                                       &options);
-       selftest(np && !strcmp("test/alias/option", options),
+       unittest(np && !strcmp("test/alias/option", options),
                 "option alias path test, subcase #1 failed\n");
        of_node_put(np);
 
        np = of_find_node_opts_by_path("testcase-alias:testaliasoption", NULL);
-       selftest(np, "NULL option alias path test failed\n");
+       unittest(np, "NULL option alias path test failed\n");
        of_node_put(np);
 
        options = "testoption";
        np = of_find_node_opts_by_path("testcase-alias", &options);
-       selftest(np && !options, "option clearing test failed\n");
+       unittest(np && !options, "option clearing test failed\n");
        of_node_put(np);
 
        options = "testoption";
        np = of_find_node_opts_by_path("/", &options);
-       selftest(np && !options, "option clearing root node test failed\n");
+       unittest(np && !options, "option clearing root node test failed\n");
        of_node_put(np);
 }
 
-static void __init of_selftest_dynamic(void)
+static void __init of_unittest_dynamic(void)
 {
        struct device_node *np;
        struct property *prop;
@@ -142,7 +147,7 @@ static void __init of_selftest_dynamic(void)
        /* Array of 4 properties for the purpose of testing */
        prop = kzalloc(sizeof(*prop) * 4, GFP_KERNEL);
        if (!prop) {
-               selftest(0, "kzalloc() failed\n");
+               unittest(0, "kzalloc() failed\n");
                return;
        }
 
@@ -150,20 +155,20 @@ static void __init of_selftest_dynamic(void)
        prop->name = "new-property";
        prop->value = "new-property-data";
        prop->length = strlen(prop->value);
-       selftest(of_add_property(np, prop) == 0, "Adding a new property failed\n");
+       unittest(of_add_property(np, prop) == 0, "Adding a new property failed\n");
 
        /* Try to add an existing property - should fail */
        prop++;
        prop->name = "new-property";
        prop->value = "new-property-data-should-fail";
        prop->length = strlen(prop->value);
-       selftest(of_add_property(np, prop) != 0,
+       unittest(of_add_property(np, prop) != 0,
                 "Adding an existing property should have failed\n");
 
        /* Try to modify an existing property - should pass */
        prop->value = "modify-property-data-should-pass";
        prop->length = strlen(prop->value);
-       selftest(of_update_property(np, prop) == 0,
+       unittest(of_update_property(np, prop) == 0,
                 "Updating an existing property should have passed\n");
 
        /* Try to modify non-existent property - should pass*/
@@ -171,11 +176,11 @@ static void __init of_selftest_dynamic(void)
        prop->name = "modify-property";
        prop->value = "modify-missing-property-data-should-pass";
        prop->length = strlen(prop->value);
-       selftest(of_update_property(np, prop) == 0,
+       unittest(of_update_property(np, prop) == 0,
                 "Updating a missing property should have passed\n");
 
        /* Remove property - should pass */
-       selftest(of_remove_property(np, prop) == 0,
+       unittest(of_remove_property(np, prop) == 0,
                 "Removing a property should have passed\n");
 
        /* Adding very large property - should pass */
@@ -183,13 +188,13 @@ static void __init of_selftest_dynamic(void)
        prop->name = "large-property-PAGE_SIZEx8";
        prop->length = PAGE_SIZE * 8;
        prop->value = kzalloc(prop->length, GFP_KERNEL);
-       selftest(prop->value != NULL, "Unable to allocate large buffer\n");
+       unittest(prop->value != NULL, "Unable to allocate large buffer\n");
        if (prop->value)
-               selftest(of_add_property(np, prop) == 0,
+               unittest(of_add_property(np, prop) == 0,
                         "Adding a large property should have passed\n");
 }
 
-static int __init of_selftest_check_node_linkage(struct device_node *np)
+static int __init of_unittest_check_node_linkage(struct device_node *np)
 {
        struct device_node *child;
        int count = 0, rc;
@@ -201,7 +206,7 @@ static int __init of_selftest_check_node_linkage(struct device_node *np)
                        return -EINVAL;
                }
 
-               rc = of_selftest_check_node_linkage(child);
+               rc = of_unittest_check_node_linkage(child);
                if (rc < 0)
                        return rc;
                count += rc;
@@ -210,7 +215,7 @@ static int __init of_selftest_check_node_linkage(struct device_node *np)
        return count + 1;
 }
 
-static void __init of_selftest_check_tree_linkage(void)
+static void __init of_unittest_check_tree_linkage(void)
 {
        struct device_node *np;
        int allnode_count = 0, child_count;
@@ -220,10 +225,10 @@ static void __init of_selftest_check_tree_linkage(void)
 
        for_each_of_allnodes(np)
                allnode_count++;
-       child_count = of_selftest_check_node_linkage(of_root);
+       child_count = of_unittest_check_node_linkage(of_root);
 
-       selftest(child_count > 0, "Device node data structure is corrupted\n");
-       selftest(child_count == allnode_count, "allnodes list size (%i) doesn't match"
+       unittest(child_count > 0, "Device node data structure is corrupted\n");
+       unittest(child_count == allnode_count, "allnodes list size (%i) doesn't match"
                 "sibling lists size (%i)\n", allnode_count, child_count);
        pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count);
 }
@@ -234,7 +239,7 @@ struct node_hash {
 };
 
 static DEFINE_HASHTABLE(phandle_ht, 8);
-static void __init of_selftest_check_phandles(void)
+static void __init of_unittest_check_phandles(void)
 {
        struct device_node *np;
        struct node_hash *nh;
@@ -262,7 +267,7 @@ static void __init of_selftest_check_phandles(void)
                hash_add(phandle_ht, &nh->node, np->phandle);
                phandle_count++;
        }
-       selftest(dup_count == 0, "Found %i duplicates in %i phandles\n",
+       unittest(dup_count == 0, "Found %i duplicates in %i phandles\n",
                 dup_count, phandle_count);
 
        /* Clean up */
@@ -272,7 +277,7 @@ static void __init of_selftest_check_phandles(void)
        }
 }
 
-static void __init of_selftest_parse_phandle_with_args(void)
+static void __init of_unittest_parse_phandle_with_args(void)
 {
        struct device_node *np;
        struct of_phandle_args args;
@@ -285,7 +290,7 @@ static void __init of_selftest_parse_phandle_with_args(void)
        }
 
        rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells");
-       selftest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);
+       unittest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);
 
        for (i = 0; i < 8; i++) {
                bool passed = true;
@@ -337,44 +342,44 @@ static void __init of_selftest_parse_phandle_with_args(void)
                        passed = false;
                }
 
-               selftest(passed, "index %i - data error on node %s rc=%i\n",
+               unittest(passed, "index %i - data error on node %s rc=%i\n",
                         i, args.np->full_name, rc);
        }
 
        /* Check for missing list property */
        rc = of_parse_phandle_with_args(np, "phandle-list-missing",
                                        "#phandle-cells", 0, &args);
-       selftest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
+       unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
        rc = of_count_phandle_with_args(np, "phandle-list-missing",
                                        "#phandle-cells");
-       selftest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
+       unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
 
        /* Check for missing cells property */
        rc = of_parse_phandle_with_args(np, "phandle-list",
                                        "#phandle-cells-missing", 0, &args);
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
        rc = of_count_phandle_with_args(np, "phandle-list",
                                        "#phandle-cells-missing");
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 
        /* Check for bad phandle in list */
        rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle",
                                        "#phandle-cells", 0, &args);
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
        rc = of_count_phandle_with_args(np, "phandle-list-bad-phandle",
                                        "#phandle-cells");
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 
        /* Check for incorrectly formed argument list */
        rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
                                        "#phandle-cells", 1, &args);
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
        rc = of_count_phandle_with_args(np, "phandle-list-bad-args",
                                        "#phandle-cells");
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 }
 
-static void __init of_selftest_property_string(void)
+static void __init of_unittest_property_string(void)
 {
        const char *strings[4];
        struct device_node *np;
@@ -387,79 +392,79 @@ static void __init of_selftest_property_string(void)
        }
 
        rc = of_property_match_string(np, "phandle-list-names", "first");
-       selftest(rc == 0, "first expected:0 got:%i\n", rc);
+       unittest(rc == 0, "first expected:0 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "second");
-       selftest(rc == 1, "second expected:1 got:%i\n", rc);
+       unittest(rc == 1, "second expected:1 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "third");
-       selftest(rc == 2, "third expected:2 got:%i\n", rc);
+       unittest(rc == 2, "third expected:2 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "fourth");
-       selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc);
+       unittest(rc == -ENODATA, "unmatched string; rc=%i\n", rc);
        rc = of_property_match_string(np, "missing-property", "blah");
-       selftest(rc == -EINVAL, "missing property; rc=%i\n", rc);
+       unittest(rc == -EINVAL, "missing property; rc=%i\n", rc);
        rc = of_property_match_string(np, "empty-property", "blah");
-       selftest(rc == -ENODATA, "empty property; rc=%i\n", rc);
+       unittest(rc == -ENODATA, "empty property; rc=%i\n", rc);
        rc = of_property_match_string(np, "unterminated-string", "blah");
-       selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
+       unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
 
        /* of_property_count_strings() tests */
        rc = of_property_count_strings(np, "string-property");
-       selftest(rc == 1, "Incorrect string count; rc=%i\n", rc);
+       unittest(rc == 1, "Incorrect string count; rc=%i\n", rc);
        rc = of_property_count_strings(np, "phandle-list-names");
-       selftest(rc == 3, "Incorrect string count; rc=%i\n", rc);
+       unittest(rc == 3, "Incorrect string count; rc=%i\n", rc);
        rc = of_property_count_strings(np, "unterminated-string");
-       selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
+       unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
        rc = of_property_count_strings(np, "unterminated-string-list");
-       selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
+       unittest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
 
        /* of_property_read_string_index() tests */
        rc = of_property_read_string_index(np, "string-property", 0, strings);
-       selftest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc);
        strings[0] = NULL;
        rc = of_property_read_string_index(np, "string-property", 1, strings);
-       selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
        rc = of_property_read_string_index(np, "phandle-list-names", 0, strings);
-       selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
        rc = of_property_read_string_index(np, "phandle-list-names", 1, strings);
-       selftest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc);
        rc = of_property_read_string_index(np, "phandle-list-names", 2, strings);
-       selftest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc);
        strings[0] = NULL;
        rc = of_property_read_string_index(np, "phandle-list-names", 3, strings);
-       selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
        strings[0] = NULL;
        rc = of_property_read_string_index(np, "unterminated-string", 0, strings);
-       selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
        rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings);
-       selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
        strings[0] = NULL;
        rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */
-       selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
        strings[1] = NULL;
 
        /* of_property_read_string_array() tests */
        rc = of_property_read_string_array(np, "string-property", strings, 4);
-       selftest(rc == 1, "Incorrect string count; rc=%i\n", rc);
+       unittest(rc == 1, "Incorrect string count; rc=%i\n", rc);
        rc = of_property_read_string_array(np, "phandle-list-names", strings, 4);
-       selftest(rc == 3, "Incorrect string count; rc=%i\n", rc);
+       unittest(rc == 3, "Incorrect string count; rc=%i\n", rc);
        rc = of_property_read_string_array(np, "unterminated-string", strings, 4);
-       selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
+       unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
        /* -- An incorrectly formed string should cause a failure */
        rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4);
-       selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
+       unittest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
        /* -- parsing the correctly formed strings should still work: */
        strings[2] = NULL;
        rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2);
-       selftest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc);
+       unittest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc);
        strings[1] = NULL;
        rc = of_property_read_string_array(np, "phandle-list-names", strings, 1);
-       selftest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]);
+       unittest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]);
 }
 
 #define propcmp(p1, p2) (((p1)->length == (p2)->length) && \
                        (p1)->value && (p2)->value && \
                        !memcmp((p1)->value, (p2)->value, (p1)->length) && \
                        !strcmp((p1)->name, (p2)->name))
-static void __init of_selftest_property_copy(void)
+static void __init of_unittest_property_copy(void)
 {
 #ifdef CONFIG_OF_DYNAMIC
        struct property p1 = { .name = "p1", .length = 0, .value = "" };
@@ -467,20 +472,20 @@ static void __init of_selftest_property_copy(void)
        struct property *new;
 
        new = __of_prop_dup(&p1, GFP_KERNEL);
-       selftest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
+       unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
        kfree(new->value);
        kfree(new->name);
        kfree(new);
 
        new = __of_prop_dup(&p2, GFP_KERNEL);
-       selftest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
+       unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
        kfree(new->value);
        kfree(new->name);
        kfree(new);
 #endif
 }
 
-static void __init of_selftest_changeset(void)
+static void __init of_unittest_changeset(void)
 {
 #ifdef CONFIG_OF_DYNAMIC
        struct property *ppadd, padd = { .name = "prop-add", .length = 0, .value = "" };
@@ -490,51 +495,51 @@ static void __init of_selftest_changeset(void)
        struct of_changeset chgset;
 
        n1 = __of_node_dup(NULL, "/testcase-data/changeset/n1");
-       selftest(n1, "testcase setup failure\n");
+       unittest(n1, "testcase setup failure\n");
        n2 = __of_node_dup(NULL, "/testcase-data/changeset/n2");
-       selftest(n2, "testcase setup failure\n");
+       unittest(n2, "testcase setup failure\n");
        n21 = __of_node_dup(NULL, "%s/%s", "/testcase-data/changeset/n2", "n21");
-       selftest(n21, "testcase setup failure %p\n", n21);
+       unittest(n21, "testcase setup failure %p\n", n21);
        nremove = of_find_node_by_path("/testcase-data/changeset/node-remove");
-       selftest(nremove, "testcase setup failure\n");
+       unittest(nremove, "testcase setup failure\n");
        ppadd = __of_prop_dup(&padd, GFP_KERNEL);
-       selftest(ppadd, "testcase setup failure\n");
+       unittest(ppadd, "testcase setup failure\n");
        ppupdate = __of_prop_dup(&pupdate, GFP_KERNEL);
-       selftest(ppupdate, "testcase setup failure\n");
+       unittest(ppupdate, "testcase setup failure\n");
        parent = nremove->parent;
        n1->parent = parent;
        n2->parent = parent;
        n21->parent = n2;
        n2->child = n21;
        ppremove = of_find_property(parent, "prop-remove", NULL);
-       selftest(ppremove, "failed to find removal prop");
+       unittest(ppremove, "failed to find removal prop");
 
        of_changeset_init(&chgset);
-       selftest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n");
-       selftest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n");
-       selftest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n");
-       selftest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n");
-       selftest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop\n");
-       selftest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n");
-       selftest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n");
+       unittest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n");
+       unittest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n");
+       unittest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n");
+       unittest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n");
+       unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop\n");
+       unittest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n");
+       unittest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n");
        mutex_lock(&of_mutex);
-       selftest(!of_changeset_apply(&chgset), "apply failed\n");
+       unittest(!of_changeset_apply(&chgset), "apply failed\n");
        mutex_unlock(&of_mutex);
 
        /* Make sure node names are constructed correctly */
-       selftest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
+       unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
                 "'%s' not added\n", n21->full_name);
        of_node_put(np);
 
        mutex_lock(&of_mutex);
-       selftest(!of_changeset_revert(&chgset), "revert failed\n");
+       unittest(!of_changeset_revert(&chgset), "revert failed\n");
        mutex_unlock(&of_mutex);
 
        of_changeset_destroy(&chgset);
 #endif
 }
 
-static void __init of_selftest_parse_interrupts(void)
+static void __init of_unittest_parse_interrupts(void)
 {
        struct device_node *np;
        struct of_phandle_args args;
@@ -555,7 +560,7 @@ static void __init of_selftest_parse_interrupts(void)
                passed &= (args.args_count == 1);
                passed &= (args.args[0] == (i + 1));
 
-               selftest(passed, "index %i - data error on node %s rc=%i\n",
+               unittest(passed, "index %i - data error on node %s rc=%i\n",
                         i, args.np->full_name, rc);
        }
        of_node_put(np);
@@ -600,13 +605,13 @@ static void __init of_selftest_parse_interrupts(void)
                default:
                        passed = false;
                }
-               selftest(passed, "index %i - data error on node %s rc=%i\n",
+               unittest(passed, "index %i - data error on node %s rc=%i\n",
                         i, args.np->full_name, rc);
        }
        of_node_put(np);
 }
 
-static void __init of_selftest_parse_interrupts_extended(void)
+static void __init of_unittest_parse_interrupts_extended(void)
 {
        struct device_node *np;
        struct of_phandle_args args;
@@ -669,7 +674,7 @@ static void __init of_selftest_parse_interrupts_extended(void)
                        passed = false;
                }
 
-               selftest(passed, "index %i - data error on node %s rc=%i\n",
+               unittest(passed, "index %i - data error on node %s rc=%i\n",
                         i, args.np->full_name, rc);
        }
        of_node_put(np);
@@ -710,7 +715,7 @@ static struct {
        { .path = "/testcase-data/match-node/name9", .data = "K", },
 };
 
-static void __init of_selftest_match_node(void)
+static void __init of_unittest_match_node(void)
 {
        struct device_node *np;
        const struct of_device_id *match;
@@ -719,32 +724,32 @@ static void __init of_selftest_match_node(void)
        for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) {
                np = of_find_node_by_path(match_node_tests[i].path);
                if (!np) {
-                       selftest(0, "missing testcase node %s\n",
+                       unittest(0, "missing testcase node %s\n",
                                match_node_tests[i].path);
                        continue;
                }
 
                match = of_match_node(match_node_table, np);
                if (!match) {
-                       selftest(0, "%s didn't match anything\n",
+                       unittest(0, "%s didn't match anything\n",
                                match_node_tests[i].path);
                        continue;
                }
 
                if (strcmp(match->data, match_node_tests[i].data) != 0) {
-                       selftest(0, "%s got wrong match. expected %s, got %s\n",
+                       unittest(0, "%s got wrong match. expected %s, got %s\n",
                                match_node_tests[i].path, match_node_tests[i].data,
                                (const char *)match->data);
                        continue;
                }
-               selftest(1, "passed");
+               unittest(1, "passed");
        }
 }
 
 struct device test_bus = {
        .init_name = "unittest-bus",
 };
-static void __init of_selftest_platform_populate(void)
+static void __init of_unittest_platform_populate(void)
 {
        int irq, rc;
        struct device_node *np, *child, *grandchild;
@@ -760,30 +765,30 @@ static void __init of_selftest_platform_populate(void)
        /* Test that a missing irq domain returns -EPROBE_DEFER */
        np = of_find_node_by_path("/testcase-data/testcase-device1");
        pdev = of_find_device_by_node(np);
-       selftest(pdev, "device 1 creation failed\n");
+       unittest(pdev, "device 1 creation failed\n");
 
        irq = platform_get_irq(pdev, 0);
-       selftest(irq == -EPROBE_DEFER, "device deferred probe failed - %d\n", irq);
+       unittest(irq == -EPROBE_DEFER, "device deferred probe failed - %d\n", irq);
 
        /* Test that a parsing failure does not return -EPROBE_DEFER */
        np = of_find_node_by_path("/testcase-data/testcase-device2");
        pdev = of_find_device_by_node(np);
-       selftest(pdev, "device 2 creation failed\n");
+       unittest(pdev, "device 2 creation failed\n");
        irq = platform_get_irq(pdev, 0);
-       selftest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq);
+       unittest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq);
 
-       if (selftest(np = of_find_node_by_path("/testcase-data/platform-tests"),
+       if (unittest(np = of_find_node_by_path("/testcase-data/platform-tests"),
                     "No testcase data in device tree\n"));
                return;
 
-       if (selftest(!(rc = device_register(&test_bus)),
+       if (unittest(!(rc = device_register(&test_bus)),
                     "testbus registration failed; rc=%i\n", rc));
                return;
 
        for_each_child_of_node(np, child) {
                of_platform_populate(child, match, NULL, &test_bus);
                for_each_child_of_node(child, grandchild)
-                       selftest(of_find_device_by_node(grandchild),
+                       unittest(of_find_device_by_node(grandchild),
                                 "Could not create device for node '%s'\n",
                                 grandchild->name);
        }
@@ -791,7 +796,7 @@ static void __init of_selftest_platform_populate(void)
        of_platform_depopulate(&test_bus);
        for_each_child_of_node(np, child) {
                for_each_child_of_node(child, grandchild)
-                       selftest(!of_find_device_by_node(grandchild),
+                       unittest(!of_find_device_by_node(grandchild),
                                 "device didn't get destroyed '%s'\n",
                                 grandchild->name);
        }
@@ -861,13 +866,13 @@ static int attach_node_and_children(struct device_node *np)
 }
 
 /**
- *     selftest_data_add - Reads, copies data from
+ *     unittest_data_add - Reads, copies data from
  *     linked tree and attaches it to the live tree
  */
-static int __init selftest_data_add(void)
+static int __init unittest_data_add(void)
 {
-       void *selftest_data;
-       struct device_node *selftest_data_node, *np;
+       void *unittest_data;
+       struct device_node *unittest_data_node, *np;
        extern uint8_t __dtb_testcases_begin[];
        extern uint8_t __dtb_testcases_end[];
        const int size = __dtb_testcases_end - __dtb_testcases_begin;
@@ -880,27 +885,27 @@ static int __init selftest_data_add(void)
        }
 
        /* creating copy */
-       selftest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL);
+       unittest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL);
 
-       if (!selftest_data) {
-               pr_warn("%s: Failed to allocate memory for selftest_data; "
+       if (!unittest_data) {
+               pr_warn("%s: Failed to allocate memory for unittest_data; "
                        "not running tests\n", __func__);
                return -ENOMEM;
        }
-       of_fdt_unflatten_tree(selftest_data, &selftest_data_node);
-       if (!selftest_data_node) {
+       of_fdt_unflatten_tree(unittest_data, &unittest_data_node);
+       if (!unittest_data_node) {
                pr_warn("%s: No tree to attach; not running tests\n", __func__);
                return -ENODATA;
        }
-       of_node_set_flag(selftest_data_node, OF_DETACHED);
-       rc = of_resolve_phandles(selftest_data_node);
+       of_node_set_flag(unittest_data_node, OF_DETACHED);
+       rc = of_resolve_phandles(unittest_data_node);
        if (rc) {
                pr_err("%s: Failed to resolve phandles (rc=%i)\n", __func__, rc);
                return -EINVAL;
        }
 
        if (!of_root) {
-               of_root = selftest_data_node;
+               of_root = unittest_data_node;
                for_each_of_allnodes(np)
                        __of_attach_node_sysfs(np);
                of_aliases = of_find_node_by_path("/aliases");
@@ -909,7 +914,7 @@ static int __init selftest_data_add(void)
        }
 
        /* attach the sub-tree to live tree */
-       np = selftest_data_node->child;
+       np = unittest_data_node->child;
        while (np) {
                struct device_node *next = np->sibling;
                np->parent = of_root;
@@ -921,7 +926,7 @@ static int __init selftest_data_add(void)
 
 #ifdef CONFIG_OF_OVERLAY
 
-static int selftest_probe(struct platform_device *pdev)
+static int unittest_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
@@ -939,7 +944,7 @@ static int selftest_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int selftest_remove(struct platform_device *pdev)
+static int unittest_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
@@ -948,18 +953,18 @@ static int selftest_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id selftest_match[] = {
-       { .compatible = "selftest", },
+static struct of_device_id unittest_match[] = {
+       { .compatible = "unittest", },
        {},
 };
 
-static struct platform_driver selftest_driver = {
-       .probe                  = selftest_probe,
-       .remove                 = selftest_remove,
+static struct platform_driver unittest_driver = {
+       .probe                  = unittest_probe,
+       .remove                 = unittest_remove,
        .driver = {
-               .name           = "selftest",
+               .name           = "unittest",
                .owner          = THIS_MODULE,
-               .of_match_table = of_match_ptr(selftest_match),
+               .of_match_table = of_match_ptr(unittest_match),
        },
 };
 
@@ -1041,7 +1046,7 @@ static int of_path_device_type_exists(const char *path,
        return 0;
 }
 
-static const char *selftest_path(int nr, enum overlay_type ovtype)
+static const char *unittest_path(int nr, enum overlay_type ovtype)
 {
        const char *base;
        static char buf[256];
@@ -1057,16 +1062,16 @@ static const char *selftest_path(int nr, enum overlay_type ovtype)
                buf[0] = '\0';
                return buf;
        }
-       snprintf(buf, sizeof(buf) - 1, "%s/test-selftest%d", base, nr);
+       snprintf(buf, sizeof(buf) - 1, "%s/test-unittest%d", base, nr);
        buf[sizeof(buf) - 1] = '\0';
        return buf;
 }
 
-static int of_selftest_device_exists(int selftest_nr, enum overlay_type ovtype)
+static int of_unittest_device_exists(int unittest_nr, enum overlay_type ovtype)
 {
        const char *path;
 
-       path = selftest_path(selftest_nr, ovtype);
+       path = unittest_path(unittest_nr, ovtype);
 
        switch (ovtype) {
        case PDEV_OVERLAY:
@@ -1090,7 +1095,7 @@ static const char *overlay_path(int nr)
 
 static const char *bus_path = "/testcase-data/overlay-node/test-bus";
 
-static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
+static int of_unittest_apply_overlay(int unittest_nr, int overlay_nr,
                int *overlay_id)
 {
        struct device_node *np = NULL;
@@ -1098,7 +1103,7 @@ static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
 
        np = of_find_node_by_path(overlay_path(overlay_nr));
        if (np == NULL) {
-               selftest(0, "could not find overlay node @\"%s\"\n",
+               unittest(0, "could not find overlay node @\"%s\"\n",
                                overlay_path(overlay_nr));
                ret = -EINVAL;
                goto out;
@@ -1106,7 +1111,7 @@ static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
 
        ret = of_overlay_create(np);
        if (ret < 0) {
-               selftest(0, "could not create overlay from \"%s\"\n",
+               unittest(0, "could not create overlay from \"%s\"\n",
                                overlay_path(overlay_nr));
                goto out;
        }
@@ -1124,31 +1129,31 @@ out:
 }
 
 /* apply an overlay while checking before and after states */
-static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr,
+static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr,
                int before, int after, enum overlay_type ovtype)
 {
        int ret;
 
-       /* selftest device must not be in before state */
-       if (of_selftest_device_exists(selftest_nr, ovtype) != before) {
-               selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+       /* unittest device must not be in before state */
+       if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
+               unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype),
+                               unittest_path(unittest_nr, ovtype),
                                !before ? "enabled" : "disabled");
                return -EINVAL;
        }
 
-       ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, NULL);
+       ret = of_unittest_apply_overlay(overlay_nr, unittest_nr, NULL);
        if (ret != 0) {
-               /* of_selftest_apply_overlay already called selftest() */
+               /* of_unittest_apply_overlay already called unittest() */
                return ret;
        }
 
-       /* selftest device must be to set to after state */
-       if (of_selftest_device_exists(selftest_nr, ovtype) != after) {
-               selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
+       /* unittest device must be to set to after state */
+       if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
+               unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype),
+                               unittest_path(unittest_nr, ovtype),
                                !after ? "enabled" : "disabled");
                return -EINVAL;
        }
@@ -1157,50 +1162,50 @@ static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr,
 }
 
 /* apply an overlay and then revert it while checking before, after states */
-static int of_selftest_apply_revert_overlay_check(int overlay_nr,
-               int selftest_nr, int before, int after,
+static int of_unittest_apply_revert_overlay_check(int overlay_nr,
+               int unittest_nr, int before, int after,
                enum overlay_type ovtype)
 {
        int ret, ov_id;
 
-       /* selftest device must be in before state */
-       if (of_selftest_device_exists(selftest_nr, ovtype) != before) {
-               selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+       /* unittest device must be in before state */
+       if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
+               unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype),
+                               unittest_path(unittest_nr, ovtype),
                                !before ? "enabled" : "disabled");
                return -EINVAL;
        }
 
        /* apply the overlay */
-       ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, &ov_id);
+       ret = of_unittest_apply_overlay(overlay_nr, unittest_nr, &ov_id);
        if (ret != 0) {
-               /* of_selftest_apply_overlay already called selftest() */
+               /* of_unittest_apply_overlay already called unittest() */
                return ret;
        }
 
-       /* selftest device must be in after state */
-       if (of_selftest_device_exists(selftest_nr, ovtype) != after) {
-               selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
+       /* unittest device must be in after state */
+       if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
+               unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype),
+                               unittest_path(unittest_nr, ovtype),
                                !after ? "enabled" : "disabled");
                return -EINVAL;
        }
 
        ret = of_overlay_destroy(ov_id);
        if (ret != 0) {
-               selftest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
+               unittest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype));
+                               unittest_path(unittest_nr, ovtype));
                return ret;
        }
 
-       /* selftest device must be again in before state */
-       if (of_selftest_device_exists(selftest_nr, PDEV_OVERLAY) != before) {
-               selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+       /* unittest device must be again in before state */
+       if (of_unittest_device_exists(unittest_nr, PDEV_OVERLAY) != before) {
+               unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype),
+                               unittest_path(unittest_nr, ovtype),
                                !before ? "enabled" : "disabled");
                return -EINVAL;
        }
@@ -1209,98 +1214,98 @@ static int of_selftest_apply_revert_overlay_check(int overlay_nr,
 }
 
 /* test activation of device */
-static void of_selftest_overlay_0(void)
+static void of_unittest_overlay_0(void)
 {
        int ret;
 
        /* device should enable */
-       ret = of_selftest_apply_overlay_check(0, 0, 0, 1, PDEV_OVERLAY);
+       ret = of_unittest_apply_overlay_check(0, 0, 0, 1, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 0);
+       unittest(1, "overlay test %d passed\n", 0);
 }
 
 /* test deactivation of device */
-static void of_selftest_overlay_1(void)
+static void of_unittest_overlay_1(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_overlay_check(1, 1, 1, 0, PDEV_OVERLAY);
+       ret = of_unittest_apply_overlay_check(1, 1, 1, 0, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 1);
+       unittest(1, "overlay test %d passed\n", 1);
 }
 
 /* test activation of device */
-static void of_selftest_overlay_2(void)
+static void of_unittest_overlay_2(void)
 {
        int ret;
 
        /* device should enable */
-       ret = of_selftest_apply_overlay_check(2, 2, 0, 1, PDEV_OVERLAY);
+       ret = of_unittest_apply_overlay_check(2, 2, 0, 1, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 2);
+       unittest(1, "overlay test %d passed\n", 2);
 }
 
 /* test deactivation of device */
-static void of_selftest_overlay_3(void)
+static void of_unittest_overlay_3(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_overlay_check(3, 3, 1, 0, PDEV_OVERLAY);
+       ret = of_unittest_apply_overlay_check(3, 3, 1, 0, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 3);
+       unittest(1, "overlay test %d passed\n", 3);
 }
 
 /* test activation of a full device node */
-static void of_selftest_overlay_4(void)
+static void of_unittest_overlay_4(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_overlay_check(4, 4, 0, 1, PDEV_OVERLAY);
+       ret = of_unittest_apply_overlay_check(4, 4, 0, 1, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 4);
+       unittest(1, "overlay test %d passed\n", 4);
 }
 
 /* test overlay apply/revert sequence */
-static void of_selftest_overlay_5(void)
+static void of_unittest_overlay_5(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1, PDEV_OVERLAY);
+       ret = of_unittest_apply_revert_overlay_check(5, 5, 0, 1, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 5);
+       unittest(1, "overlay test %d passed\n", 5);
 }
 
 /* test overlay application in sequence */
-static void of_selftest_overlay_6(void)
+static void of_unittest_overlay_6(void)
 {
        struct device_node *np;
        int ret, i, ov_id[2];
-       int overlay_nr = 6, selftest_nr = 6;
+       int overlay_nr = 6, unittest_nr = 6;
        int before = 0, after = 1;
 
-       /* selftest device must be in before state */
+       /* unittest device must be in before state */
        for (i = 0; i < 2; i++) {
-               if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY)
+               if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
                                != before) {
-                       selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+                       unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
                                        overlay_path(overlay_nr + i),
-                                       selftest_path(selftest_nr + i,
+                                       unittest_path(unittest_nr + i,
                                                PDEV_OVERLAY),
                                        !before ? "enabled" : "disabled");
                        return;
@@ -1312,14 +1317,14 @@ static void of_selftest_overlay_6(void)
 
                np = of_find_node_by_path(overlay_path(overlay_nr + i));
                if (np == NULL) {
-                       selftest(0, "could not find overlay node @\"%s\"\n",
+                       unittest(0, "could not find overlay node @\"%s\"\n",
                                        overlay_path(overlay_nr + i));
                        return;
                }
 
                ret = of_overlay_create(np);
                if (ret < 0)  {
-                       selftest(0, "could not create overlay from \"%s\"\n",
+                       unittest(0, "could not create overlay from \"%s\"\n",
                                        overlay_path(overlay_nr + i));
                        return;
                }
@@ -1327,12 +1332,12 @@ static void of_selftest_overlay_6(void)
        }
 
        for (i = 0; i < 2; i++) {
-               /* selftest device must be in after state */
-               if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY)
+               /* unittest device must be in after state */
+               if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
                                != after) {
-                       selftest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
+                       unittest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
                                        overlay_path(overlay_nr + i),
-                                       selftest_path(selftest_nr + i,
+                                       unittest_path(unittest_nr + i,
                                                PDEV_OVERLAY),
                                        !after ? "enabled" : "disabled");
                        return;
@@ -1342,36 +1347,36 @@ static void of_selftest_overlay_6(void)
        for (i = 1; i >= 0; i--) {
                ret = of_overlay_destroy(ov_id[i]);
                if (ret != 0) {
-                       selftest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
+                       unittest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
                                        overlay_path(overlay_nr + i),
-                                       selftest_path(selftest_nr + i,
+                                       unittest_path(unittest_nr + i,
                                                PDEV_OVERLAY));
                        return;
                }
        }
 
        for (i = 0; i < 2; i++) {
-               /* selftest device must be again in before state */
-               if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY)
+               /* unittest device must be again in before state */
+               if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
                                != before) {
-                       selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+                       unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
                                        overlay_path(overlay_nr + i),
-                                       selftest_path(selftest_nr + i,
+                                       unittest_path(unittest_nr + i,
                                                PDEV_OVERLAY),
                                        !before ? "enabled" : "disabled");
                        return;
                }
        }
 
-       selftest(1, "overlay test %d passed\n", 6);
+       unittest(1, "overlay test %d passed\n", 6);
 }
 
 /* test overlay application in sequence */
-static void of_selftest_overlay_8(void)
+static void of_unittest_overlay_8(void)
 {
        struct device_node *np;
        int ret, i, ov_id[2];
-       int overlay_nr = 8, selftest_nr = 8;
+       int overlay_nr = 8, unittest_nr = 8;
 
        /* we don't care about device state in this test */
 
@@ -1380,14 +1385,14 @@ static void of_selftest_overlay_8(void)
 
                np = of_find_node_by_path(overlay_path(overlay_nr + i));
                if (np == NULL) {
-                       selftest(0, "could not find overlay node @\"%s\"\n",
+                       unittest(0, "could not find overlay node @\"%s\"\n",
                                        overlay_path(overlay_nr + i));
                        return;
                }
 
                ret = of_overlay_create(np);
                if (ret < 0)  {
-                       selftest(0, "could not create overlay from \"%s\"\n",
+                       unittest(0, "could not create overlay from \"%s\"\n",
                                        overlay_path(overlay_nr + i));
                        return;
                }
@@ -1397,9 +1402,9 @@ static void of_selftest_overlay_8(void)
        /* now try to remove first overlay (it should fail) */
        ret = of_overlay_destroy(ov_id[0]);
        if (ret == 0) {
-               selftest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
+               unittest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
                                overlay_path(overlay_nr + 0),
-                               selftest_path(selftest_nr,
+                               unittest_path(unittest_nr,
                                        PDEV_OVERLAY));
                return;
        }
@@ -1408,85 +1413,85 @@ static void of_selftest_overlay_8(void)
        for (i = 1; i >= 0; i--) {
                ret = of_overlay_destroy(ov_id[i]);
                if (ret != 0) {
-                       selftest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
+                       unittest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
                                        overlay_path(overlay_nr + i),
-                                       selftest_path(selftest_nr,
+                                       unittest_path(unittest_nr,
                                                PDEV_OVERLAY));
                        return;
                }
        }
 
-       selftest(1, "overlay test %d passed\n", 8);
+       unittest(1, "overlay test %d passed\n", 8);
 }
 
 /* test insertion of a bus with parent devices */
-static void of_selftest_overlay_10(void)
+static void of_unittest_overlay_10(void)
 {
        int ret;
        char *child_path;
 
        /* device should disable */
-       ret = of_selftest_apply_overlay_check(10, 10, 0, 1, PDEV_OVERLAY);
-       if (selftest(ret == 0,
+       ret = of_unittest_apply_overlay_check(10, 10, 0, 1, PDEV_OVERLAY);
+       if (unittest(ret == 0,
                        "overlay test %d failed; overlay application\n", 10))
                return;
 
-       child_path = kasprintf(GFP_KERNEL, "%s/test-selftest101",
-                       selftest_path(10, PDEV_OVERLAY));
-       if (selftest(child_path, "overlay test %d failed; kasprintf\n", 10))
+       child_path = kasprintf(GFP_KERNEL, "%s/test-unittest101",
+                       unittest_path(10, PDEV_OVERLAY));
+       if (unittest(child_path, "overlay test %d failed; kasprintf\n", 10))
                return;
 
        ret = of_path_device_type_exists(child_path, PDEV_OVERLAY);
        kfree(child_path);
-       if (selftest(ret, "overlay test %d failed; no child device\n", 10))
+       if (unittest(ret, "overlay test %d failed; no child device\n", 10))
                return;
 }
 
 /* test insertion of a bus with parent devices (and revert) */
-static void of_selftest_overlay_11(void)
+static void of_unittest_overlay_11(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_revert_overlay_check(11, 11, 0, 1,
+       ret = of_unittest_apply_revert_overlay_check(11, 11, 0, 1,
                        PDEV_OVERLAY);
-       if (selftest(ret == 0,
+       if (unittest(ret == 0,
                        "overlay test %d failed; overlay application\n", 11))
                return;
 }
 
 #if IS_BUILTIN(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY)
 
-struct selftest_i2c_bus_data {
+struct unittest_i2c_bus_data {
        struct platform_device  *pdev;
        struct i2c_adapter      adap;
 };
 
-static int selftest_i2c_master_xfer(struct i2c_adapter *adap,
+static int unittest_i2c_master_xfer(struct i2c_adapter *adap,
                struct i2c_msg *msgs, int num)
 {
-       struct selftest_i2c_bus_data *std = i2c_get_adapdata(adap);
+       struct unittest_i2c_bus_data *std = i2c_get_adapdata(adap);
 
        (void)std;
 
        return num;
 }
 
-static u32 selftest_i2c_functionality(struct i2c_adapter *adap)
+static u32 unittest_i2c_functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 }
 
-static const struct i2c_algorithm selftest_i2c_algo = {
-       .master_xfer    = selftest_i2c_master_xfer,
-       .functionality  = selftest_i2c_functionality,
+static const struct i2c_algorithm unittest_i2c_algo = {
+       .master_xfer    = unittest_i2c_master_xfer,
+       .functionality  = unittest_i2c_functionality,
 };
 
-static int selftest_i2c_bus_probe(struct platform_device *pdev)
+static int unittest_i2c_bus_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
-       struct selftest_i2c_bus_data *std;
+       struct unittest_i2c_bus_data *std;
        struct i2c_adapter *adap;
        int ret;
 
@@ -1500,7 +1505,7 @@ static int selftest_i2c_bus_probe(struct platform_device *pdev)
 
        std = devm_kzalloc(dev, sizeof(*std), GFP_KERNEL);
        if (!std) {
-               dev_err(dev, "Failed to allocate selftest i2c data\n");
+               dev_err(dev, "Failed to allocate unittest i2c data\n");
                return -ENOMEM;
        }
 
@@ -1513,7 +1518,7 @@ static int selftest_i2c_bus_probe(struct platform_device *pdev)
        adap->nr = -1;
        strlcpy(adap->name, pdev->name, sizeof(adap->name));
        adap->class = I2C_CLASS_DEPRECATED;
-       adap->algo = &selftest_i2c_algo;
+       adap->algo = &unittest_i2c_algo;
        adap->dev.parent = dev;
        adap->dev.of_node = dev->of_node;
        adap->timeout = 5 * HZ;
@@ -1528,11 +1533,11 @@ static int selftest_i2c_bus_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int selftest_i2c_bus_remove(struct platform_device *pdev)
+static int unittest_i2c_bus_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
-       struct selftest_i2c_bus_data *std = platform_get_drvdata(pdev);
+       struct unittest_i2c_bus_data *std = platform_get_drvdata(pdev);
 
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
        i2c_del_adapter(&std->adap);
@@ -1540,21 +1545,21 @@ static int selftest_i2c_bus_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id selftest_i2c_bus_match[] = {
-       { .compatible = "selftest-i2c-bus", },
+static struct of_device_id unittest_i2c_bus_match[] = {
+       { .compatible = "unittest-i2c-bus", },
        {},
 };
 
-static struct platform_driver selftest_i2c_bus_driver = {
-       .probe                  = selftest_i2c_bus_probe,
-       .remove                 = selftest_i2c_bus_remove,
+static struct platform_driver unittest_i2c_bus_driver = {
+       .probe                  = unittest_i2c_bus_probe,
+       .remove                 = unittest_i2c_bus_remove,
        .driver = {
-               .name           = "selftest-i2c-bus",
-               .of_match_table = of_match_ptr(selftest_i2c_bus_match),
+               .name           = "unittest-i2c-bus",
+               .of_match_table = of_match_ptr(unittest_i2c_bus_match),
        },
 };
 
-static int selftest_i2c_dev_probe(struct i2c_client *client,
+static int unittest_i2c_dev_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        struct device *dev = &client->dev;
@@ -1570,7 +1575,7 @@ static int selftest_i2c_dev_probe(struct i2c_client *client,
        return 0;
 };
 
-static int selftest_i2c_dev_remove(struct i2c_client *client)
+static int unittest_i2c_dev_remove(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
        struct device_node *np = client->dev.of_node;
@@ -1579,42 +1584,42 @@ static int selftest_i2c_dev_remove(struct i2c_client *client)
        return 0;
 }
 
-static const struct i2c_device_id selftest_i2c_dev_id[] = {
-       { .name = "selftest-i2c-dev" },
+static const struct i2c_device_id unittest_i2c_dev_id[] = {
+       { .name = "unittest-i2c-dev" },
        { }
 };
 
-static struct i2c_driver selftest_i2c_dev_driver = {
+static struct i2c_driver unittest_i2c_dev_driver = {
        .driver = {
-               .name = "selftest-i2c-dev",
+               .name = "unittest-i2c-dev",
                .owner = THIS_MODULE,
        },
-       .probe = selftest_i2c_dev_probe,
-       .remove = selftest_i2c_dev_remove,
-       .id_table = selftest_i2c_dev_id,
+       .probe = unittest_i2c_dev_probe,
+       .remove = unittest_i2c_dev_remove,
+       .id_table = unittest_i2c_dev_id,
 };
 
 #if IS_BUILTIN(CONFIG_I2C_MUX)
 
-struct selftest_i2c_mux_data {
+struct unittest_i2c_mux_data {
        int nchans;
        struct i2c_adapter *adap[];
 };
 
-static int selftest_i2c_mux_select_chan(struct i2c_adapter *adap,
+static int unittest_i2c_mux_select_chan(struct i2c_adapter *adap,
                               void *client, u32 chan)
 {
        return 0;
 }
 
-static int selftest_i2c_mux_probe(struct i2c_client *client,
+static int unittest_i2c_mux_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        int ret, i, nchans, size;
        struct device *dev = &client->dev;
        struct i2c_adapter *adap = to_i2c_adapter(dev->parent);
        struct device_node *np = client->dev.of_node, *child;
-       struct selftest_i2c_mux_data *stm;
+       struct unittest_i2c_mux_data *stm;
        u32 reg, max_reg;
 
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
@@ -1638,7 +1643,7 @@ static int selftest_i2c_mux_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
-       size = offsetof(struct selftest_i2c_mux_data, adap[nchans]);
+       size = offsetof(struct unittest_i2c_mux_data, adap[nchans]);
        stm = devm_kzalloc(dev, size, GFP_KERNEL);
        if (!stm) {
                dev_err(dev, "Out of memory\n");
@@ -1647,7 +1652,7 @@ static int selftest_i2c_mux_probe(struct i2c_client *client,
        stm->nchans = nchans;
        for (i = 0; i < nchans; i++) {
                stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
-                               0, i, 0, selftest_i2c_mux_select_chan, NULL);
+                               0, i, 0, unittest_i2c_mux_select_chan, NULL);
                if (!stm->adap[i]) {
                        dev_err(dev, "Failed to register mux #%d\n", i);
                        for (i--; i >= 0; i--)
@@ -1661,11 +1666,11 @@ static int selftest_i2c_mux_probe(struct i2c_client *client,
        return 0;
 };
 
-static int selftest_i2c_mux_remove(struct i2c_client *client)
+static int unittest_i2c_mux_remove(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
        struct device_node *np = client->dev.of_node;
-       struct selftest_i2c_mux_data *stm = i2c_get_clientdata(client);
+       struct unittest_i2c_mux_data *stm = i2c_get_clientdata(client);
        int i;
 
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
@@ -1674,166 +1679,166 @@ static int selftest_i2c_mux_remove(struct i2c_client *client)
        return 0;
 }
 
-static const struct i2c_device_id selftest_i2c_mux_id[] = {
-       { .name = "selftest-i2c-mux" },
+static const struct i2c_device_id unittest_i2c_mux_id[] = {
+       { .name = "unittest-i2c-mux" },
        { }
 };
 
-static struct i2c_driver selftest_i2c_mux_driver = {
+static struct i2c_driver unittest_i2c_mux_driver = {
        .driver = {
-               .name = "selftest-i2c-mux",
+               .name = "unittest-i2c-mux",
                .owner = THIS_MODULE,
        },
-       .probe = selftest_i2c_mux_probe,
-       .remove = selftest_i2c_mux_remove,
-       .id_table = selftest_i2c_mux_id,
+       .probe = unittest_i2c_mux_probe,
+       .remove = unittest_i2c_mux_remove,
+       .id_table = unittest_i2c_mux_id,
 };
 
 #endif
 
-static int of_selftest_overlay_i2c_init(void)
+static int of_unittest_overlay_i2c_init(void)
 {
        int ret;
 
-       ret = i2c_add_driver(&selftest_i2c_dev_driver);
-       if (selftest(ret == 0,
-                       "could not register selftest i2c device driver\n"))
+       ret = i2c_add_driver(&unittest_i2c_dev_driver);
+       if (unittest(ret == 0,
+                       "could not register unittest i2c device driver\n"))
                return ret;
 
-       ret = platform_driver_register(&selftest_i2c_bus_driver);
-       if (selftest(ret == 0,
-                       "could not register selftest i2c bus driver\n"))
+       ret = platform_driver_register(&unittest_i2c_bus_driver);
+       if (unittest(ret == 0,
+                       "could not register unittest i2c bus driver\n"))
                return ret;
 
 #if IS_BUILTIN(CONFIG_I2C_MUX)
-       ret = i2c_add_driver(&selftest_i2c_mux_driver);
-       if (selftest(ret == 0,
-                       "could not register selftest i2c mux driver\n"))
+       ret = i2c_add_driver(&unittest_i2c_mux_driver);
+       if (unittest(ret == 0,
+                       "could not register unittest i2c mux driver\n"))
                return ret;
 #endif
 
        return 0;
 }
 
-static void of_selftest_overlay_i2c_cleanup(void)
+static void of_unittest_overlay_i2c_cleanup(void)
 {
 #if IS_BUILTIN(CONFIG_I2C_MUX)
-       i2c_del_driver(&selftest_i2c_mux_driver);
+       i2c_del_driver(&unittest_i2c_mux_driver);
 #endif
-       platform_driver_unregister(&selftest_i2c_bus_driver);
-       i2c_del_driver(&selftest_i2c_dev_driver);
+       platform_driver_unregister(&unittest_i2c_bus_driver);
+       i2c_del_driver(&unittest_i2c_dev_driver);
 }
 
-static void of_selftest_overlay_i2c_12(void)
+static void of_unittest_overlay_i2c_12(void)
 {
        int ret;
 
        /* device should enable */
-       ret = of_selftest_apply_overlay_check(12, 12, 0, 1, I2C_OVERLAY);
+       ret = of_unittest_apply_overlay_check(12, 12, 0, 1, I2C_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 12);
+       unittest(1, "overlay test %d passed\n", 12);
 }
 
 /* test deactivation of device */
-static void of_selftest_overlay_i2c_13(void)
+static void of_unittest_overlay_i2c_13(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_overlay_check(13, 13, 1, 0, I2C_OVERLAY);
+       ret = of_unittest_apply_overlay_check(13, 13, 1, 0, I2C_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 13);
+       unittest(1, "overlay test %d passed\n", 13);
 }
 
 /* just check for i2c mux existence */
-static void of_selftest_overlay_i2c_14(void)
+static void of_unittest_overlay_i2c_14(void)
 {
 }
 
-static void of_selftest_overlay_i2c_15(void)
+static void of_unittest_overlay_i2c_15(void)
 {
        int ret;
 
        /* device should enable */
-       ret = of_selftest_apply_overlay_check(16, 15, 0, 1, I2C_OVERLAY);
+       ret = of_unittest_apply_overlay_check(16, 15, 0, 1, I2C_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 15);
+       unittest(1, "overlay test %d passed\n", 15);
 }
 
 #else
 
-static inline void of_selftest_overlay_i2c_14(void) { }
-static inline void of_selftest_overlay_i2c_15(void) { }
+static inline void of_unittest_overlay_i2c_14(void) { }
+static inline void of_unittest_overlay_i2c_15(void) { }
 
 #endif
 
-static void __init of_selftest_overlay(void)
+static void __init of_unittest_overlay(void)
 {
        struct device_node *bus_np = NULL;
        int ret;
 
-       ret = platform_driver_register(&selftest_driver);
+       ret = platform_driver_register(&unittest_driver);
        if (ret != 0) {
-               selftest(0, "could not register selftest driver\n");
+               unittest(0, "could not register unittest driver\n");
                goto out;
        }
 
        bus_np = of_find_node_by_path(bus_path);
        if (bus_np == NULL) {
-               selftest(0, "could not find bus_path \"%s\"\n", bus_path);
+               unittest(0, "could not find bus_path \"%s\"\n", bus_path);
                goto out;
        }
 
        ret = of_platform_populate(bus_np, of_default_bus_match_table,
                        NULL, NULL);
        if (ret != 0) {
-               selftest(0, "could not populate bus @ \"%s\"\n", bus_path);
+               unittest(0, "could not populate bus @ \"%s\"\n", bus_path);
                goto out;
        }
 
-       if (!of_selftest_device_exists(100, PDEV_OVERLAY)) {
-               selftest(0, "could not find selftest0 @ \"%s\"\n",
-                               selftest_path(100, PDEV_OVERLAY));
+       if (!of_unittest_device_exists(100, PDEV_OVERLAY)) {
+               unittest(0, "could not find unittest0 @ \"%s\"\n",
+                               unittest_path(100, PDEV_OVERLAY));
                goto out;
        }
 
-       if (of_selftest_device_exists(101, PDEV_OVERLAY)) {
-               selftest(0, "selftest1 @ \"%s\" should not exist\n",
-                               selftest_path(101, PDEV_OVERLAY));
+       if (of_unittest_device_exists(101, PDEV_OVERLAY)) {
+               unittest(0, "unittest1 @ \"%s\" should not exist\n",
+                               unittest_path(101, PDEV_OVERLAY));
                goto out;
        }
 
-       selftest(1, "basic infrastructure of overlays passed");
+       unittest(1, "basic infrastructure of overlays passed");
 
        /* tests in sequence */
-       of_selftest_overlay_0();
-       of_selftest_overlay_1();
-       of_selftest_overlay_2();
-       of_selftest_overlay_3();
-       of_selftest_overlay_4();
-       of_selftest_overlay_5();
-       of_selftest_overlay_6();
-       of_selftest_overlay_8();
-
-       of_selftest_overlay_10();
-       of_selftest_overlay_11();
+       of_unittest_overlay_0();
+       of_unittest_overlay_1();
+       of_unittest_overlay_2();
+       of_unittest_overlay_3();
+       of_unittest_overlay_4();
+       of_unittest_overlay_5();
+       of_unittest_overlay_6();
+       of_unittest_overlay_8();
+
+       of_unittest_overlay_10();
+       of_unittest_overlay_11();
 
 #if IS_BUILTIN(CONFIG_I2C)
-       if (selftest(of_selftest_overlay_i2c_init() == 0, "i2c init failed\n"))
+       if (unittest(of_unittest_overlay_i2c_init() == 0, "i2c init failed\n"))
                goto out;
 
-       of_selftest_overlay_i2c_12();
-       of_selftest_overlay_i2c_13();
-       of_selftest_overlay_i2c_14();
-       of_selftest_overlay_i2c_15();
+       of_unittest_overlay_i2c_12();
+       of_unittest_overlay_i2c_13();
+       of_unittest_overlay_i2c_14();
+       of_unittest_overlay_i2c_15();
 
-       of_selftest_overlay_i2c_cleanup();
+       of_unittest_overlay_i2c_cleanup();
 #endif
 
 out:
@@ -1841,16 +1846,16 @@ out:
 }
 
 #else
-static inline void __init of_selftest_overlay(void) { }
+static inline void __init of_unittest_overlay(void) { }
 #endif
 
-static int __init of_selftest(void)
+static int __init of_unittest(void)
 {
        struct device_node *np;
        int res;
 
-       /* adding data for selftest */
-       res = selftest_data_add();
+       /* adding data for unittest */
+       res = unittest_data_add();
        if (res)
                return res;
        if (!of_aliases)
@@ -1863,27 +1868,27 @@ static int __init of_selftest(void)
        }
        of_node_put(np);
 
-       pr_info("start of selftest - you will see error messages\n");
-       of_selftest_check_tree_linkage();
-       of_selftest_check_phandles();
-       of_selftest_find_node_by_name();
-       of_selftest_dynamic();
-       of_selftest_parse_phandle_with_args();
-       of_selftest_property_string();
-       of_selftest_property_copy();
-       of_selftest_changeset();
-       of_selftest_parse_interrupts();
-       of_selftest_parse_interrupts_extended();
-       of_selftest_match_node();
-       of_selftest_platform_populate();
-       of_selftest_overlay();
+       pr_info("start of unittest - you will see error messages\n");
+       of_unittest_check_tree_linkage();
+       of_unittest_check_phandles();
+       of_unittest_find_node_by_name();
+       of_unittest_dynamic();
+       of_unittest_parse_phandle_with_args();
+       of_unittest_property_string();
+       of_unittest_property_copy();
+       of_unittest_changeset();
+       of_unittest_parse_interrupts();
+       of_unittest_parse_interrupts_extended();
+       of_unittest_match_node();
+       of_unittest_platform_populate();
+       of_unittest_overlay();
 
        /* Double check linkage after removing testcase data */
-       of_selftest_check_tree_linkage();
+       of_unittest_check_tree_linkage();
 
-       pr_info("end of selftest - %i passed, %i failed\n",
-               selftest_results.passed, selftest_results.failed);
+       pr_info("end of unittest - %i passed, %i failed\n",
+               unittest_results.passed, unittest_results.failed);
 
        return 0;
 }
-late_initcall(of_selftest);
+late_initcall(of_unittest);
index 3bb4925..45f67c6 100644 (file)
@@ -69,8 +69,7 @@ config YENTA
        tristate "CardBus yenta-compatible bridge support"
        depends on PCI
        select CARDBUS if !EXPERT
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC if PCMCIA != n
        ---help---
          This option enables support for CardBus host bridges.  Virtually
          all modern PCMCIA bridges are CardBus compatible.  A "bridge" is
@@ -110,8 +109,7 @@ config YENTA_TOSHIBA
 config PD6729
        tristate "Cirrus PD6729 compatible bridge support"
        depends on PCMCIA && PCI
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC
        help
          This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge
          device, found in some older laptops and PCMCIA card readers.
@@ -119,8 +117,7 @@ config PD6729
 config I82092
        tristate "i82092 compatible bridge support"
        depends on PCMCIA && PCI
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC
        help
          This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
          found in some older laptops and more commonly in evaluation boards for the
@@ -291,9 +288,6 @@ config ELECTRA_CF
          Say Y here to support the CompactFlash controller on the
          PA Semi Electra eval board.
 
-config PCCARD_PCI
-       bool
-
 config PCCARD_NONSTATIC
        bool
 
index f1a7ca0..27e94b3 100644 (file)
@@ -12,7 +12,6 @@ obj-$(CONFIG_PCMCIA)                          += pcmcia.o
 pcmcia_rsrc-y                                  += rsrc_mgr.o
 pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC)         += rsrc_nonstatic.o
 pcmcia_rsrc-$(CONFIG_PCCARD_IODYN)             += rsrc_iodyn.o
-pcmcia_rsrc-$(CONFIG_PCCARD_PCI)               += rsrc_pci.o
 obj-$(CONFIG_PCCARD)                           += pcmcia_rsrc.o
 
 
diff --git a/drivers/pcmcia/rsrc_pci.c b/drivers/pcmcia/rsrc_pci.c
deleted file mode 100644 (file)
index 1f67b3b..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-
-#include <pcmcia/ss.h>
-#include <pcmcia/cistpl.h>
-#include "cs_internal.h"
-
-
-struct pcmcia_align_data {
-       unsigned long   mask;
-       unsigned long   offset;
-};
-
-static resource_size_t pcmcia_align(void *align_data,
-                               const struct resource *res,
-                               resource_size_t size, resource_size_t align)
-{
-       struct pcmcia_align_data *data = align_data;
-       resource_size_t start;
-
-       start = (res->start & ~data->mask) + data->offset;
-       if (start < res->start)
-               start += data->mask + 1;
-       return start;
-}
-
-static struct resource *find_io_region(struct pcmcia_socket *s,
-                                       unsigned long base, int num,
-                                       unsigned long align)
-{
-       struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
-                                               dev_name(&s->dev));
-       struct pcmcia_align_data data;
-       int ret;
-
-       data.mask = align - 1;
-       data.offset = base & data.mask;
-
-       ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
-                                            base, 0, pcmcia_align, &data);
-       if (ret != 0) {
-               kfree(res);
-               res = NULL;
-       }
-       return res;
-}
-
-static int res_pci_find_io(struct pcmcia_socket *s, unsigned int attr,
-                       unsigned int *base, unsigned int num,
-                       unsigned int align, struct resource **parent)
-{
-       int i, ret = 0;
-
-       /* Check for an already-allocated window that must conflict with
-        * what was asked for.  It is a hack because it does not catch all
-        * potential conflicts, just the most obvious ones.
-        */
-       for (i = 0; i < MAX_IO_WIN; i++) {
-               if (!s->io[i].res)
-                       continue;
-
-               if (!*base)
-                       continue;
-
-               if ((s->io[i].res->start & (align-1)) == *base)
-                       return -EBUSY;
-       }
-
-       for (i = 0; i < MAX_IO_WIN; i++) {
-               struct resource *res = s->io[i].res;
-               unsigned int try;
-
-               if (res && (res->flags & IORESOURCE_BITS) !=
-                       (attr & IORESOURCE_BITS))
-                       continue;
-
-               if (!res) {
-                       if (align == 0)
-                               align = 0x10000;
-
-                       res = s->io[i].res = find_io_region(s, *base, num,
-                                                               align);
-                       if (!res)
-                               return -EINVAL;
-
-                       *base = res->start;
-                       s->io[i].res->flags =
-                               ((res->flags & ~IORESOURCE_BITS) |
-                                       (attr & IORESOURCE_BITS));
-                       s->io[i].InUse = num;
-                       *parent = res;
-                       return 0;
-               }
-
-               /* Try to extend top of window */
-               try = res->end + 1;
-               if ((*base == 0) || (*base == try)) {
-                       ret = adjust_resource(s->io[i].res, res->start,
-                                             resource_size(res) + num);
-                       if (ret)
-                               continue;
-                       *base = try;
-                       s->io[i].InUse += num;
-                       *parent = res;
-                       return 0;
-               }
-
-               /* Try to extend bottom of window */
-               try = res->start - num;
-               if ((*base == 0) || (*base == try)) {
-                       ret = adjust_resource(s->io[i].res,
-                                             res->start - num,
-                                             resource_size(res) + num);
-                       if (ret)
-                               continue;
-                       *base = try;
-                       s->io[i].InUse += num;
-                       *parent = res;
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static struct resource *res_pci_find_mem(u_long base, u_long num,
-               u_long align, int low, struct pcmcia_socket *s)
-{
-       struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
-                                               dev_name(&s->dev));
-       struct pcmcia_align_data data;
-       unsigned long min;
-       int ret;
-
-       if (align < 0x20000)
-               align = 0x20000;
-       data.mask = align - 1;
-       data.offset = base & data.mask;
-
-       min = 0;
-       if (!low)
-               min = 0x100000UL;
-
-       ret = pci_bus_alloc_resource(s->cb_dev->bus,
-                       res, num, 1, min, 0,
-                       pcmcia_align, &data);
-
-       if (ret != 0) {
-               kfree(res);
-               res = NULL;
-       }
-       return res;
-}
-
-
-static int res_pci_init(struct pcmcia_socket *s)
-{
-       if (!s->cb_dev || !(s->features & SS_CAP_PAGE_REGS)) {
-               dev_err(&s->dev, "not supported by res_pci\n");
-               return -EOPNOTSUPP;
-       }
-       return 0;
-}
-
-struct pccard_resource_ops pccard_nonstatic_ops = {
-       .validate_mem = NULL,
-       .find_io = res_pci_find_io,
-       .find_mem = res_pci_find_mem,
-       .init = res_pci_init,
-       .exit = NULL,
-};
-EXPORT_SYMBOL(pccard_nonstatic_ops);
index 7c99ca2..8ccc395 100644 (file)
@@ -37,7 +37,7 @@ static int armada375_usb_phy_init(struct phy *phy)
        struct armada375_cluster_phy *cluster_phy;
        u32 reg;
 
-       cluster_phy = dev_get_drvdata(phy->dev.parent);
+       cluster_phy = phy_get_drvdata(phy);
        if (!cluster_phy)
                return -ENODEV;
 
@@ -131,6 +131,7 @@ static int armada375_usb_phy_probe(struct platform_device *pdev)
        cluster_phy->reg = usb_cluster_base;
 
        dev_set_drvdata(dev, cluster_phy);
+       phy_set_drvdata(phy, cluster_phy);
 
        phy_provider = devm_of_phy_provider_register(&pdev->dev,
                                                     armada375_usb_phy_xlate);
index a12d353..3791838 100644 (file)
@@ -52,7 +52,9 @@ static void devm_phy_consume(struct device *dev, void *res)
 
 static int devm_phy_match(struct device *dev, void *res, void *match_data)
 {
-       return res == match_data;
+       struct phy **phy = res;
+
+       return *phy == match_data;
 }
 
 /**
@@ -223,6 +225,7 @@ int phy_init(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->init_count == 0 && phy->ops->init) {
@@ -231,8 +234,6 @@ int phy_init(struct phy *phy)
                        dev_err(&phy->dev, "phy init failed --> %d\n", ret);
                        goto out;
                }
-       } else {
-               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->init_count;
 
@@ -253,6 +254,7 @@ int phy_exit(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->init_count == 1 && phy->ops->exit) {
@@ -287,6 +289,7 @@ int phy_power_on(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->power_count == 0 && phy->ops->power_on) {
@@ -295,8 +298,6 @@ int phy_power_on(struct phy *phy)
                        dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
                        goto out;
                }
-       } else {
-               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->power_count;
        mutex_unlock(&phy->mutex);
index f86cbe6..179cbf9 100644 (file)
@@ -30,28 +30,13 @@ struct exynos_dp_video_phy {
        const struct exynos_dp_video_phy_drvdata *drvdata;
 };
 
-static void exynos_dp_video_phy_pwr_isol(struct exynos_dp_video_phy *state,
-                                                       unsigned int on)
-{
-       unsigned int val;
-
-       if (IS_ERR(state->regs))
-               return;
-
-       val = on ? 0 : EXYNOS5_PHY_ENABLE;
-
-       regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
-                          EXYNOS5_PHY_ENABLE, val);
-}
-
 static int exynos_dp_video_phy_power_on(struct phy *phy)
 {
        struct exynos_dp_video_phy *state = phy_get_drvdata(phy);
 
        /* Disable power isolation on DP-PHY */
-       exynos_dp_video_phy_pwr_isol(state, 0);
-
-       return 0;
+       return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
+                                 EXYNOS5_PHY_ENABLE, EXYNOS5_PHY_ENABLE);
 }
 
 static int exynos_dp_video_phy_power_off(struct phy *phy)
@@ -59,9 +44,8 @@ static int exynos_dp_video_phy_power_off(struct phy *phy)
        struct exynos_dp_video_phy *state = phy_get_drvdata(phy);
 
        /* Enable power isolation on DP-PHY */
-       exynos_dp_video_phy_pwr_isol(state, 1);
-
-       return 0;
+       return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
+                                 EXYNOS5_PHY_ENABLE, 0);
 }
 
 static struct phy_ops exynos_dp_video_phy_ops = {
index f017b2f..df7519a 100644 (file)
@@ -43,7 +43,6 @@ struct exynos_mipi_video_phy {
        } phys[EXYNOS_MIPI_PHYS_NUM];
        spinlock_t slock;
        void __iomem *regs;
-       struct mutex mutex;
        struct regmap *regmap;
 };
 
@@ -59,8 +58,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
        else
                reset = EXYNOS4_MIPI_PHY_SRESETN;
 
-       if (state->regmap) {
-               mutex_lock(&state->mutex);
+       spin_lock(&state->slock);
+
+       if (!IS_ERR(state->regmap)) {
                regmap_read(state->regmap, offset, &val);
                if (on)
                        val |= reset;
@@ -72,11 +72,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
                else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
                        val &= ~EXYNOS4_MIPI_PHY_ENABLE;
                regmap_write(state->regmap, offset, val);
-               mutex_unlock(&state->mutex);
        } else {
                addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
 
-               spin_lock(&state->slock);
                val = readl(addr);
                if (on)
                        val |= reset;
@@ -90,9 +88,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
                        val &= ~EXYNOS4_MIPI_PHY_ENABLE;
 
                writel(val, addr);
-               spin_unlock(&state->slock);
        }
 
+       spin_unlock(&state->slock);
        return 0;
 }
 
@@ -158,7 +156,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
 
        dev_set_drvdata(dev, state);
        spin_lock_init(&state->slock);
-       mutex_init(&state->mutex);
 
        for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
                struct phy *phy = devm_phy_create(dev, NULL,
index 236a52a..f30bbb0 100644 (file)
@@ -250,7 +250,6 @@ static const struct samsung_usb2_common_phy exynos4210_phys[] = {
                .power_on       = exynos4210_power_on,
                .power_off      = exynos4210_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
index 0b9de88..765da90 100644 (file)
@@ -361,7 +361,6 @@ static const struct samsung_usb2_common_phy exynos4x12_phys[] = {
                .power_on       = exynos4x12_power_on,
                .power_off      = exynos4x12_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos3250_usb2_phy_config = {
index 0437401..e2a0be7 100644 (file)
@@ -531,7 +531,7 @@ static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev,
 {
        struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev);
 
-       if (WARN_ON(args->args[0] > EXYNOS5_DRDPHYS_NUM))
+       if (WARN_ON(args->args[0] >= EXYNOS5_DRDPHYS_NUM))
                return ERR_PTR(-ENODEV);
 
        return phy_drd->phys[args->args[0]].phy;
index 1c139aa..2ed1735 100644 (file)
@@ -391,7 +391,6 @@ static const struct samsung_usb2_common_phy exynos5250_phys[] = {
                .power_on       = exynos5250_power_on,
                .power_off      = exynos5250_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
index 34915b4..d6b2265 100644 (file)
@@ -147,6 +147,9 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
        priv->base = devm_ioremap(dev, res->start, resource_size(res));
        if (!priv->base)
                return -ENOMEM;
index 9b2848e..9334352 100644 (file)
@@ -228,6 +228,7 @@ struct miphy28lp_dev {
        struct regmap *regmap;
        struct mutex miphy_mutex;
        struct miphy28lp_phy **phys;
+       int nphys;
 };
 
 struct miphy_initval {
@@ -1116,7 +1117,7 @@ static struct phy *miphy28lp_xlate(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       for (index = 0; index < of_get_child_count(dev->of_node); index++)
+       for (index = 0; index < miphy_dev->nphys; index++)
                if (phynode == miphy_dev->phys[index]->phy->dev.of_node) {
                        miphy_phy = miphy_dev->phys[index];
                        break;
@@ -1138,6 +1139,7 @@ static struct phy *miphy28lp_xlate(struct device *dev,
 
 static struct phy_ops miphy28lp_ops = {
        .init = miphy28lp_init,
+       .owner = THIS_MODULE,
 };
 
 static int miphy28lp_probe_resets(struct device_node *node,
@@ -1200,16 +1202,15 @@ static int miphy28lp_probe(struct platform_device *pdev)
        struct miphy28lp_dev *miphy_dev;
        struct phy_provider *provider;
        struct phy *phy;
-       int chancount, port = 0;
-       int ret;
+       int ret, port = 0;
 
        miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
        if (!miphy_dev)
                return -ENOMEM;
 
-       chancount = of_get_child_count(np);
-       miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount,
-                                      GFP_KERNEL);
+       miphy_dev->nphys = of_get_child_count(np);
+       miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys,
+                                      sizeof(*miphy_dev->phys), GFP_KERNEL);
        if (!miphy_dev->phys)
                return -ENOMEM;
 
index 6c80154..51b459d 100644 (file)
@@ -150,6 +150,7 @@ struct miphy365x_dev {
        struct regmap *regmap;
        struct mutex miphy_mutex;
        struct miphy365x_phy **phys;
+       int nphys;
 };
 
 /*
@@ -485,7 +486,7 @@ static struct phy *miphy365x_xlate(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       for (index = 0; index < of_get_child_count(dev->of_node); index++)
+       for (index = 0; index < miphy_dev->nphys; index++)
                if (phynode == miphy_dev->phys[index]->phy->dev.of_node) {
                        miphy_phy = miphy_dev->phys[index];
                        break;
@@ -541,16 +542,15 @@ static int miphy365x_probe(struct platform_device *pdev)
        struct miphy365x_dev *miphy_dev;
        struct phy_provider *provider;
        struct phy *phy;
-       int chancount, port = 0;
-       int ret;
+       int ret, port = 0;
 
        miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
        if (!miphy_dev)
                return -ENOMEM;
 
-       chancount = of_get_child_count(np);
-       miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount,
-                                      GFP_KERNEL);
+       miphy_dev->nphys = of_get_child_count(np);
+       miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys,
+                                      sizeof(*miphy_dev->phys), GFP_KERNEL);
        if (!miphy_dev->phys)
                return -ENOMEM;
 
index efe724f..93252e0 100644 (file)
@@ -360,7 +360,7 @@ static void __exit omap_control_phy_exit(void)
 }
 module_exit(omap_control_phy_exit);
 
-MODULE_ALIAS("platform: omap_control_phy");
+MODULE_ALIAS("platform:omap_control_phy");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("OMAP Control Module PHY Driver");
 MODULE_LICENSE("GPL v2");
index 6f4aef3..4757e76 100644 (file)
@@ -296,10 +296,11 @@ static int omap_usb2_probe(struct platform_device *pdev)
                        dev_warn(&pdev->dev,
                                 "found usb_otg_ss_refclk960m, please fix DTS\n");
                }
-       } else {
-               clk_prepare(phy->optclk);
        }
 
+       if (!IS_ERR(phy->optclk))
+               clk_prepare(phy->optclk);
+
        usb_add_phy_dev(&phy->phy);
 
        return 0;
@@ -383,7 +384,7 @@ static struct platform_driver omap_usb2_driver = {
 
 module_platform_driver(omap_usb2_driver);
 
-MODULE_ALIAS("platform: omap_usb2");
+MODULE_ALIAS("platform:omap_usb2");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("OMAP USB2 phy driver");
 MODULE_LICENSE("GPL v2");
index 22011c3..7d4c336 100644 (file)
@@ -61,8 +61,6 @@ static int rockchip_usb_phy_power_off(struct phy *_phy)
                return ret;
 
        clk_disable_unprepare(phy->clk);
-       if (ret)
-               return ret;
 
        return 0;
 }
@@ -78,8 +76,10 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
 
        /* Power up usb phy analog blocks by set siddq 0 */
        ret = rockchip_usb_phy_power(phy, 0);
-       if (ret)
+       if (ret) {
+               clk_disable_unprepare(phy->clk);
                return ret;
+       }
 
        return 0;
 }
index 95c88f9..2ba610b 100644 (file)
@@ -165,15 +165,11 @@ static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy)
                cpu_relax();
                val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
                if (val & PLL_LOCK)
-                       break;
+                       return 0;
        } while (!time_after(jiffies, timeout));
 
-       if (!(val & PLL_LOCK)) {
-               dev_err(phy->dev, "DPLL failed to lock\n");
-               return -EBUSY;
-       }
-
-       return 0;
+       dev_err(phy->dev, "DPLL failed to lock\n");
+       return -EBUSY;
 }
 
 static int ti_pipe3_dpll_program(struct ti_pipe3 *phy)
@@ -608,7 +604,7 @@ static struct platform_driver ti_pipe3_driver = {
 
 module_platform_driver(ti_pipe3_driver);
 
-MODULE_ALIAS("platform: ti_pipe3");
+MODULE_ALIAS("platform:ti_pipe3");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("TI PIPE3 phy driver");
 MODULE_LICENSE("GPL v2");
index 8e87f54..bc42d6a 100644 (file)
@@ -666,7 +666,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        twl->dev                = &pdev->dev;
        twl->irq                = platform_get_irq(pdev, 0);
        twl->vbus_supplied      = false;
-       twl->linkstat           = -EINVAL;
        twl->linkstat           = OMAP_MUSB_UNKNOWN;
 
        twl->phy.dev            = twl->dev;
index 29214a3..2263cd0 100644 (file)
@@ -1704,7 +1704,6 @@ static int xgene_phy_probe(struct platform_device *pdev)
        for (i = 0; i < MAX_LANE; i++)
                ctx->sata_param.speed[i] = 2; /* Default to Gen3 */
 
-       ctx->dev = &pdev->dev;
        platform_set_drvdata(pdev, ctx);
 
        ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops);
index 5afe03e..2062c22 100644 (file)
 #define BYT_DIR_MASK           (BIT(1) | BIT(2))
 #define BYT_TRIG_MASK          (BIT(26) | BIT(25) | BIT(24))
 
+#define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | \
+                                BYT_PIN_MUX)
+#define BYT_VAL_RESTORE_MASK   (BYT_DIR_MASK | BYT_LEVEL)
+
 #define BYT_NGPIO_SCORE                102
 #define BYT_NGPIO_NCORE                28
 #define BYT_NGPIO_SUS          44
@@ -134,12 +138,18 @@ static struct pinctrl_gpio_range byt_ranges[] = {
        },
 };
 
+struct byt_gpio_pin_context {
+       u32 conf0;
+       u32 val;
+};
+
 struct byt_gpio {
        struct gpio_chip                chip;
        struct platform_device          *pdev;
        spinlock_t                      lock;
        void __iomem                    *reg_base;
        struct pinctrl_gpio_range       *range;
+       struct byt_gpio_pin_context     *saved_context;
 };
 
 #define to_byt_gpio(c) container_of(c, struct byt_gpio, chip)
@@ -158,40 +168,62 @@ static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
        return vg->reg_base + reg_offset + reg;
 }
 
-static bool is_special_pin(struct byt_gpio *vg, unsigned offset)
+static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned offset)
+{
+       void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+       unsigned long flags;
+       u32 value;
+
+       spin_lock_irqsave(&vg->lock, flags);
+       value = readl(reg);
+       value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
+       writel(value, reg);
+       spin_unlock_irqrestore(&vg->lock, flags);
+}
+
+static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset)
 {
        /* SCORE pin 92-93 */
        if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) &&
                offset >= 92 && offset <= 93)
-               return true;
+               return 1;
 
        /* SUS pin 11-21 */
        if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) &&
                offset >= 11 && offset <= 21)
-               return true;
+               return 1;
 
-       return false;
+       return 0;
 }
 
 static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
        struct byt_gpio *vg = to_byt_gpio(chip);
        void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
-       u32 value;
-       bool special;
+       u32 value, gpio_mux;
 
        /*
         * In most cases, func pin mux 000 means GPIO function.
         * But, some pins may have func pin mux 001 represents
-        * GPIO function. Only allow user to export pin with
-        * func pin mux preset as GPIO function by BIOS/FW.
+        * GPIO function.
+        *
+        * Because there are devices out there where some pins were not
+        * configured correctly we allow changing the mux value from
+        * request (but print out warning about that).
         */
        value = readl(reg) & BYT_PIN_MUX;
-       special = is_special_pin(vg, offset);
-       if ((special && value != 1) || (!special && value)) {
-               dev_err(&vg->pdev->dev,
-                       "pin %u cannot be used as GPIO.\n", offset);
-               return -EINVAL;
+       gpio_mux = byt_get_gpio_mux(vg, offset);
+       if (WARN_ON(gpio_mux != value)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&vg->lock, flags);
+               value = readl(reg) & ~BYT_PIN_MUX;
+               value |= gpio_mux;
+               writel(value, reg);
+               spin_unlock_irqrestore(&vg->lock, flags);
+
+               dev_warn(&vg->pdev->dev,
+                        "pin %u forcibly re-configured as GPIO\n", offset);
        }
 
        pm_runtime_get(&vg->pdev->dev);
@@ -202,14 +234,8 @@ static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
        struct byt_gpio *vg = to_byt_gpio(chip);
-       void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
-       u32 value;
-
-       /* clear interrupt triggering */
-       value = readl(reg);
-       value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
-       writel(value, reg);
 
+       byt_gpio_clear_triggering(vg, offset);
        pm_runtime_put(&vg->pdev->dev);
 }
 
@@ -236,23 +262,13 @@ static int byt_irq_type(struct irq_data *d, unsigned type)
        value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG |
                   BYT_TRIG_LVL);
 
-       switch (type) {
-       case IRQ_TYPE_LEVEL_HIGH:
-               value |= BYT_TRIG_LVL;
-       case IRQ_TYPE_EDGE_RISING:
-               value |= BYT_TRIG_POS;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               value |= BYT_TRIG_LVL;
-       case IRQ_TYPE_EDGE_FALLING:
-               value |= BYT_TRIG_NEG;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
-               break;
-       }
        writel(value, reg);
 
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
+       else if (type & IRQ_TYPE_LEVEL_MASK)
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+
        spin_unlock_irqrestore(&vg->lock, flags);
 
        return 0;
@@ -410,58 +426,80 @@ static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
        struct irq_data *data = irq_desc_get_irq_data(desc);
        struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc));
        struct irq_chip *chip = irq_data_get_irq_chip(data);
-       u32 base, pin, mask;
+       u32 base, pin;
        void __iomem *reg;
-       u32 pending;
+       unsigned long pending;
        unsigned virq;
-       int looplimit = 0;
 
        /* check from GPIO controller which pin triggered the interrupt */
        for (base = 0; base < vg->chip.ngpio; base += 32) {
-
                reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
-
-               while ((pending = readl(reg))) {
-                       pin = __ffs(pending);
-                       mask = BIT(pin);
-                       /* Clear before handling so we can't lose an edge */
-                       writel(mask, reg);
-
+               pending = readl(reg);
+               for_each_set_bit(pin, &pending, 32) {
                        virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
                        generic_handle_irq(virq);
-
-                       /* In case bios or user sets triggering incorretly a pin
-                        * might remain in "interrupt triggered" state.
-                        */
-                       if (looplimit++ > 32) {
-                               dev_err(&vg->pdev->dev,
-                                       "Gpio %d interrupt flood, disabling\n",
-                                       base + pin);
-
-                               reg = byt_gpio_reg(&vg->chip, base + pin,
-                                                  BYT_CONF0_REG);
-                               mask = readl(reg);
-                               mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS |
-                                         BYT_TRIG_LVL);
-                               writel(mask, reg);
-                               mask = readl(reg); /* flush */
-                               break;
-                       }
                }
        }
        chip->irq_eoi(data);
 }
 
+static void byt_irq_ack(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+       unsigned offset = irqd_to_hwirq(d);
+       void __iomem *reg;
+
+       reg = byt_gpio_reg(&vg->chip, offset, BYT_INT_STAT_REG);
+       writel(BIT(offset % 32), reg);
+}
+
 static void byt_irq_unmask(struct irq_data *d)
 {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+       unsigned offset = irqd_to_hwirq(d);
+       unsigned long flags;
+       void __iomem *reg;
+       u32 value;
+
+       spin_lock_irqsave(&vg->lock, flags);
+
+       reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+       value = readl(reg);
+
+       switch (irqd_get_trigger_type(d)) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               value |= BYT_TRIG_LVL;
+       case IRQ_TYPE_EDGE_RISING:
+               value |= BYT_TRIG_POS;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               value |= BYT_TRIG_LVL;
+       case IRQ_TYPE_EDGE_FALLING:
+               value |= BYT_TRIG_NEG;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
+               break;
+       }
+
+       writel(value, reg);
+
+       spin_unlock_irqrestore(&vg->lock, flags);
 }
 
 static void byt_irq_mask(struct irq_data *d)
 {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+
+       byt_gpio_clear_triggering(vg, irqd_to_hwirq(d));
 }
 
 static struct irq_chip byt_irqchip = {
        .name = "BYT-GPIO",
+       .irq_ack = byt_irq_ack,
        .irq_mask = byt_irq_mask,
        .irq_unmask = byt_irq_unmask,
        .irq_set_type = byt_irq_type,
@@ -472,6 +510,21 @@ static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
 {
        void __iomem *reg;
        u32 base, value;
+       int i;
+
+       /*
+        * Clear interrupt triggers for all pins that are GPIOs and
+        * do not use direct IRQ mode. This will prevent spurious
+        * interrupts from misconfigured pins.
+        */
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               value = readl(byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG));
+               if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i) &&
+                   !(value & BYT_DIRECT_IRQ_EN)) {
+                       byt_gpio_clear_triggering(vg, i);
+                       dev_dbg(&vg->pdev->dev, "disabling GPIO %d\n", i);
+               }
+       }
 
        /* clear interrupt status trigger registers */
        for (base = 0; base < vg->chip.ngpio; base += 32) {
@@ -541,6 +594,11 @@ static int byt_gpio_probe(struct platform_device *pdev)
        gc->can_sleep = false;
        gc->dev = dev;
 
+#ifdef CONFIG_PM_SLEEP
+       vg->saved_context = devm_kcalloc(&pdev->dev, gc->ngpio,
+                                      sizeof(*vg->saved_context), GFP_KERNEL);
+#endif
+
        ret = gpiochip_add(gc);
        if (ret) {
                dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
@@ -569,6 +627,69 @@ static int byt_gpio_probe(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int byt_gpio_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct byt_gpio *vg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               void __iomem *reg;
+               u32 value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG);
+               value = readl(reg) & BYT_CONF0_RESTORE_MASK;
+               vg->saved_context[i].conf0 = value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_VAL_REG);
+               value = readl(reg) & BYT_VAL_RESTORE_MASK;
+               vg->saved_context[i].val = value;
+       }
+
+       return 0;
+}
+
+static int byt_gpio_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct byt_gpio *vg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               void __iomem *reg;
+               u32 value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG);
+               value = readl(reg);
+               if ((value & BYT_CONF0_RESTORE_MASK) !=
+                    vg->saved_context[i].conf0) {
+                       value &= ~BYT_CONF0_RESTORE_MASK;
+                       value |= vg->saved_context[i].conf0;
+                       writel(value, reg);
+                       dev_info(dev, "restored pin %d conf0 %#08x", i, value);
+               }
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_VAL_REG);
+               value = readl(reg);
+               if ((value & BYT_VAL_RESTORE_MASK) !=
+                    vg->saved_context[i].val) {
+                       u32 v;
+
+                       v = value & ~BYT_VAL_RESTORE_MASK;
+                       v |= vg->saved_context[i].val;
+                       if (v != value) {
+                               writel(v, reg);
+                               dev_dbg(dev, "restored pin %d val %#08x\n",
+                                       i, v);
+                       }
+               }
+       }
+
+       return 0;
+}
+#endif
+
 static int byt_gpio_runtime_suspend(struct device *dev)
 {
        return 0;
@@ -580,8 +701,9 @@ static int byt_gpio_runtime_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops byt_gpio_pm_ops = {
-       .runtime_suspend = byt_gpio_runtime_suspend,
-       .runtime_resume = byt_gpio_runtime_resume,
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(byt_gpio_suspend, byt_gpio_resume)
+       SET_RUNTIME_PM_OPS(byt_gpio_runtime_suspend, byt_gpio_runtime_resume,
+                          NULL)
 };
 
 static const struct acpi_device_id byt_gpio_acpi_match[] = {
index 3034fd0..82f691e 100644 (file)
@@ -1226,6 +1226,7 @@ static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
                                     int value)
 {
+       chv_gpio_set(chip, offset, value);
        return pinctrl_gpio_direction_output(chip->base + offset);
 }
 
index f4cd0b9..a481406 100644 (file)
@@ -1477,28 +1477,25 @@ static void gpio_irq_ack(struct irq_data *d)
        /* the interrupt is already cleared before by reading ISR */
 }
 
-static unsigned int gpio_irq_startup(struct irq_data *d)
+static int gpio_irq_request_res(struct irq_data *d)
 {
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
        unsigned        pin = d->hwirq;
        int ret;
 
        ret = gpiochip_lock_as_irq(&at91_gpio->chip, pin);
-       if (ret) {
+       if (ret)
                dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n",
                        d->hwirq);
-               return ret;
-       }
-       gpio_irq_unmask(d);
-       return 0;
+
+       return ret;
 }
 
-static void gpio_irq_shutdown(struct irq_data *d)
+static void gpio_irq_release_res(struct irq_data *d)
 {
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
        unsigned        pin = d->hwirq;
 
-       gpio_irq_mask(d);
        gpiochip_unlock_as_irq(&at91_gpio->chip, pin);
 }
 
@@ -1577,8 +1574,8 @@ void at91_pinctrl_gpio_resume(void)
 static struct irq_chip gpio_irqchip = {
        .name           = "GPIO",
        .irq_ack        = gpio_irq_ack,
-       .irq_startup    = gpio_irq_startup,
-       .irq_shutdown   = gpio_irq_shutdown,
+       .irq_request_resources = gpio_irq_request_res,
+       .irq_release_resources = gpio_irq_release_res,
        .irq_disable    = gpio_irq_mask,
        .irq_mask       = gpio_irq_mask,
        .irq_unmask     = gpio_irq_unmask,
index 24c5d88..3c68a8e 100644 (file)
@@ -1011,6 +1011,7 @@ static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
        .pins = sun4i_a10_pins,
        .npins = ARRAY_SIZE(sun4i_a10_pins),
        .irq_banks = 1,
+       .irq_read_needs_mux = true,
 };
 
 static int sun4i_a10_pinctrl_probe(struct platform_device *pdev)
index 3d07443..f8e171b 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 
 #include "../core.h"
+#include "../../gpio/gpiolib.h"
 #include "pinctrl-sunxi.h"
 
 static struct irq_chip sunxi_pinctrl_edge_irq_chip;
@@ -464,10 +465,19 @@ static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
 static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
-
        u32 reg = sunxi_data_reg(offset);
        u8 index = sunxi_data_offset(offset);
-       u32 val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+       u32 set_mux = pctl->desc->irq_read_needs_mux &&
+                       test_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
+       u32 val;
+
+       if (set_mux)
+               sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_INPUT);
+
+       val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+
+       if (set_mux)
+               sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_IRQ);
 
        return val;
 }
index 5a51523..e248e81 100644 (file)
@@ -77,6 +77,9 @@
 #define IRQ_LEVEL_LOW          0x03
 #define IRQ_EDGE_BOTH          0x04
 
+#define SUN4I_FUNC_INPUT       0
+#define SUN4I_FUNC_IRQ         6
+
 struct sunxi_desc_function {
        const char      *name;
        u8              muxval;
@@ -94,6 +97,7 @@ struct sunxi_pinctrl_desc {
        int                             npins;
        unsigned                        pin_base;
        unsigned                        irq_banks;
+       bool                            irq_read_needs_mux;
 };
 
 struct sunxi_pinctrl_function {
index 97b5e4e..63d4033 100644 (file)
@@ -73,7 +73,7 @@
 
 #define TIME_WINDOW_MAX_MSEC 40000
 #define TIME_WINDOW_MIN_MSEC 250
-
+#define ENERGY_UNIT_SCALE    1000 /* scale from driver unit to powercap unit */
 enum unit_type {
        ARBITRARY_UNIT, /* no translation */
        POWER_UNIT,
@@ -158,6 +158,7 @@ struct rapl_domain {
        struct rapl_power_limit rpl[NR_POWER_LIMITS];
        u64 attr_map; /* track capabilities */
        unsigned int state;
+       unsigned int domain_energy_unit;
        int package_id;
 };
 #define power_zone_to_rapl_domain(_zone) \
@@ -190,6 +191,7 @@ struct rapl_defaults {
        void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
        u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
                                bool to_raw);
+       unsigned int dram_domain_energy_unit;
 };
 static struct rapl_defaults *rapl_defaults;
 
@@ -227,7 +229,8 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
 static int rapl_write_data_raw(struct rapl_domain *rd,
                        enum rapl_primitives prim,
                        unsigned long long value);
-static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
+static u64 rapl_unit_xlate(struct rapl_domain *rd, int package,
+                       enum unit_type type, u64 value,
                        int to_raw);
 static void package_power_limit_irq_save(int package_id);
 
@@ -305,7 +308,9 @@ static int get_energy_counter(struct powercap_zone *power_zone, u64 *energy_raw)
 
 static int get_max_energy_counter(struct powercap_zone *pcd_dev, u64 *energy)
 {
-       *energy = rapl_unit_xlate(0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
+       struct rapl_domain *rd = power_zone_to_rapl_domain(pcd_dev);
+
+       *energy = rapl_unit_xlate(rd, 0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
        return 0;
 }
 
@@ -639,6 +644,11 @@ static void rapl_init_domains(struct rapl_package *rp)
                        rd->msrs[4] = MSR_DRAM_POWER_INFO;
                        rd->rpl[0].prim_id = PL1_ENABLE;
                        rd->rpl[0].name = pl1_name;
+                       rd->domain_energy_unit =
+                               rapl_defaults->dram_domain_energy_unit;
+                       if (rd->domain_energy_unit)
+                               pr_info("DRAM domain energy unit %dpj\n",
+                                       rd->domain_energy_unit);
                        break;
                }
                if (mask) {
@@ -648,11 +658,13 @@ static void rapl_init_domains(struct rapl_package *rp)
        }
 }
 
-static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
+static u64 rapl_unit_xlate(struct rapl_domain *rd, int package,
+                       enum unit_type type, u64 value,
                        int to_raw)
 {
        u64 units = 1;
        struct rapl_package *rp;
+       u64 scale = 1;
 
        rp = find_package_by_id(package);
        if (!rp)
@@ -663,7 +675,12 @@ static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
                units = rp->power_unit;
                break;
        case ENERGY_UNIT:
-               units = rp->energy_unit;
+               scale = ENERGY_UNIT_SCALE;
+               /* per domain unit takes precedence */
+               if (rd && rd->domain_energy_unit)
+                       units = rd->domain_energy_unit;
+               else
+                       units = rp->energy_unit;
                break;
        case TIME_UNIT:
                return rapl_defaults->compute_time_window(rp, value, to_raw);
@@ -673,11 +690,11 @@ static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
        };
 
        if (to_raw)
-               return div64_u64(value, units);
+               return div64_u64(value, units) * scale;
 
        value *= units;
 
-       return value;
+       return div64_u64(value, scale);
 }
 
 /* in the order of enum rapl_primitives */
@@ -773,7 +790,7 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
        final = value & rp->mask;
        final = final >> rp->shift;
        if (xlate)
-               *data = rapl_unit_xlate(rd->package_id, rp->unit, final, 0);
+               *data = rapl_unit_xlate(rd, rd->package_id, rp->unit, final, 0);
        else
                *data = final;
 
@@ -799,7 +816,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
                        "failed to read msr 0x%x on cpu %d\n", msr, cpu);
                return -EIO;
        }
-       value = rapl_unit_xlate(rd->package_id, rp->unit, value, 1);
+       value = rapl_unit_xlate(rd, rd->package_id, rp->unit, value, 1);
        msr_val &= ~rp->mask;
        msr_val |= value << rp->shift;
        if (wrmsrl_safe_on_cpu(cpu, msr, msr_val)) {
@@ -818,7 +835,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
  * calculate units differ on different CPUs.
  * We convert the units to below format based on CPUs.
  * i.e.
- * energy unit: microJoules : Represented in microJoules by default
+ * energy unit: picoJoules  : Represented in picoJoules by default
  * power unit : microWatts  : Represented in milliWatts by default
  * time unit  : microseconds: Represented in seconds by default
  */
@@ -834,7 +851,7 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
        }
 
        value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
-       rp->energy_unit = 1000000 / (1 << value);
+       rp->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value);
 
        value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
        rp->power_unit = 1000000 / (1 << value);
@@ -842,7 +859,7 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
        value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
        rp->time_unit = 1000000 / (1 << value);
 
-       pr_debug("Core CPU package %d energy=%duJ, time=%dus, power=%duW\n",
+       pr_debug("Core CPU package %d energy=%dpJ, time=%dus, power=%duW\n",
                rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
 
        return 0;
@@ -859,7 +876,7 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
                return -ENODEV;
        }
        value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
-       rp->energy_unit = 1 << value;
+       rp->energy_unit = ENERGY_UNIT_SCALE * 1 << value;
 
        value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
        rp->power_unit = (1 << value) * 1000;
@@ -867,7 +884,7 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
        value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
        rp->time_unit = 1000000 / (1 << value);
 
-       pr_debug("Atom package %d energy=%duJ, time=%dus, power=%duW\n",
+       pr_debug("Atom package %d energy=%dpJ, time=%dus, power=%duW\n",
                rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
 
        return 0;
@@ -1017,6 +1034,13 @@ static const struct rapl_defaults rapl_defaults_core = {
        .compute_time_window = rapl_compute_time_window_core,
 };
 
+static const struct rapl_defaults rapl_defaults_hsw_server = {
+       .check_unit = rapl_check_unit_core,
+       .set_floor_freq = set_floor_freq_default,
+       .compute_time_window = rapl_compute_time_window_core,
+       .dram_domain_energy_unit = 15300,
+};
+
 static const struct rapl_defaults rapl_defaults_atom = {
        .check_unit = rapl_check_unit_atom,
        .set_floor_freq = set_floor_freq_atom,
@@ -1037,7 +1061,7 @@ static const struct x86_cpu_id rapl_ids[] = {
        RAPL_CPU(0x3a, rapl_defaults_core),/* Ivy Bridge */
        RAPL_CPU(0x3c, rapl_defaults_core),/* Haswell */
        RAPL_CPU(0x3d, rapl_defaults_core),/* Broadwell */
-       RAPL_CPU(0x3f, rapl_defaults_core),/* Haswell */
+       RAPL_CPU(0x3f, rapl_defaults_hsw_server),/* Haswell servers */
        RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */
        RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */
        RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */
index 1245dca..a4a8a6d 100644 (file)
@@ -1839,10 +1839,12 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
        }
 
        if (rdev->ena_pin) {
-               ret = regulator_ena_gpio_ctrl(rdev, true);
-               if (ret < 0)
-                       return ret;
-               rdev->ena_gpio_state = 1;
+               if (!rdev->ena_gpio_state) {
+                       ret = regulator_ena_gpio_ctrl(rdev, true);
+                       if (ret < 0)
+                               return ret;
+                       rdev->ena_gpio_state = 1;
+               }
        } else if (rdev->desc->ops->enable) {
                ret = rdev->desc->ops->enable(rdev);
                if (ret < 0)
@@ -1939,10 +1941,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
        trace_regulator_disable(rdev_get_name(rdev));
 
        if (rdev->ena_pin) {
-               ret = regulator_ena_gpio_ctrl(rdev, false);
-               if (ret < 0)
-                       return ret;
-               rdev->ena_gpio_state = 0;
+               if (rdev->ena_gpio_state) {
+                       ret = regulator_ena_gpio_ctrl(rdev, false);
+                       if (ret < 0)
+                               return ret;
+                       rdev->ena_gpio_state = 0;
+               }
 
        } else if (rdev->desc->ops->disable) {
                ret = rdev->desc->ops->disable(rdev);
@@ -3626,12 +3630,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
                                 config->ena_gpio, ret);
                        goto wash;
                }
-
-               if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
-                       rdev->ena_gpio_state = 1;
-
-               if (config->ena_gpio_invert)
-                       rdev->ena_gpio_state = !rdev->ena_gpio_state;
        }
 
        /* set regulator constraints */
@@ -3800,9 +3798,11 @@ int regulator_suspend_finish(void)
        list_for_each_entry(rdev, &regulator_list, list) {
                mutex_lock(&rdev->mutex);
                if (rdev->use_count > 0  || rdev->constraints->always_on) {
-                       error = _regulator_do_enable(rdev);
-                       if (error)
-                               ret = error;
+                       if (!_regulator_is_enabled(rdev)) {
+                               error = _regulator_do_enable(rdev);
+                               if (error)
+                                       ret = error;
+                       }
                } else {
                        if (!have_full_constraints())
                                goto unlock;
index 9205f43..1819831 100644 (file)
@@ -1572,6 +1572,10 @@ static int palmas_regulators_probe(struct platform_device *pdev)
        if (!pmic)
                return -ENOMEM;
 
+       if (of_device_is_compatible(node, "ti,tps659038-pmic"))
+               palmas_generic_regs_info[PALMAS_REG_REGEN2].ctrl_addr =
+                                                       TPS659038_REGEN2_CTRL;
+
        pmic->dev = &pdev->dev;
        pmic->palmas = palmas;
        palmas->pmic = pmic;
index e2cffe0..fb991ec 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
index 92f6af6..73354ee 100644 (file)
@@ -951,6 +951,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
        void *bufs_va;
        int err = 0, i;
        size_t total_buf_space;
+       bool notify;
 
        vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
        if (!vrp)
@@ -1030,8 +1031,22 @@ static int rpmsg_probe(struct virtio_device *vdev)
                }
        }
 
+       /*
+        * Prepare to kick but don't notify yet - we can't do this before
+        * device is ready.
+        */
+       notify = virtqueue_kick_prepare(vrp->rvq);
+
+       /* From this point on, we can notify and get callbacks. */
+       virtio_device_ready(vdev);
+
        /* tell the remote processor it can start sending messages */
-       virtqueue_kick(vrp->rvq);
+       /*
+        * this might be concurrent with callbacks, but we are only
+        * doing notify, not a full kick here, so that's ok.
+        */
+       if (notify)
+               virtqueue_notify(vrp->rvq);
 
        dev_info(&vdev->dev, "rpmsg host is online\n");
 
index b4f7744..b283a1a 100644 (file)
@@ -324,7 +324,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
 
                ret = IRQ_HANDLED;
        }
-       spin_lock(&suspended_lock);
+       spin_unlock(&suspended_lock);
 
        return ret;
 }
index e2436d1..3a6fd3a 100644 (file)
@@ -413,8 +413,8 @@ static void rtc_mrst_do_remove(struct device *dev)
        mrst->dev = NULL;
 }
 
-#ifdef CONFIG_PM
-static int mrst_suspend(struct device *dev, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int mrst_suspend(struct device *dev)
 {
        struct mrst_rtc *mrst = dev_get_drvdata(dev);
        unsigned char   tmp;
@@ -453,7 +453,7 @@ static int mrst_suspend(struct device *dev, pm_message_t mesg)
  */
 static inline int mrst_poweroff(struct device *dev)
 {
-       return mrst_suspend(dev, PMSG_HIBERNATE);
+       return mrst_suspend(dev);
 }
 
 static int mrst_resume(struct device *dev)
@@ -490,9 +490,11 @@ static int mrst_resume(struct device *dev)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(mrst_pm_ops, mrst_suspend, mrst_resume);
+#define MRST_PM_OPS (&mrst_pm_ops)
+
 #else
-#define        mrst_suspend    NULL
-#define        mrst_resume     NULL
+#define MRST_PM_OPS NULL
 
 static inline int mrst_poweroff(struct device *dev)
 {
@@ -529,9 +531,8 @@ static struct platform_driver vrtc_mrst_platform_driver = {
        .remove         = vrtc_mrst_platform_remove,
        .shutdown       = vrtc_mrst_platform_shutdown,
        .driver = {
-               .name           = (char *) driver_name,
-               .suspend        = mrst_suspend,
-               .resume         = mrst_resume,
+               .name   = driver_name,
+               .pm     = MRST_PM_OPS,
        }
 };
 
index 9219953..d9afc51 100644 (file)
@@ -6815,7 +6815,8 @@ static struct ata_port_operations ipr_sata_ops = {
 };
 
 static struct ata_port_info sata_port_info = {
-       .flags          = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
+       .flags          = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA |
+                         ATA_FLAG_SAS_HOST,
        .pio_mask       = ATA_PIO4_ONLY,
        .mwdma_mask     = ATA_MWDMA2,
        .udma_mask      = ATA_UDMA6,
index 932d9cc..9c706d8 100644 (file)
@@ -547,7 +547,8 @@ static struct ata_port_operations sas_sata_ops = {
 };
 
 static struct ata_port_info sata_port_info = {
-       .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ,
+       .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ |
+                ATA_FLAG_SAS_HOST,
        .pio_mask = ATA_PIO4,
        .mwdma_mask = ATA_MWDMA2,
        .udma_mask = ATA_UDMA6,
index 99f43b7..ab4879e 100644 (file)
@@ -1596,7 +1596,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
        /*
         * Finally register the new FC Nexus with TCM
         */
-       __transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess);
+       transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess);
 
        return 0;
 }
index 3ce39d1..4f8c798 100644 (file)
@@ -108,7 +108,8 @@ static void dw_spi_dma_tx_done(void *arg)
 {
        struct dw_spi *dws = arg;
 
-       if (test_and_clear_bit(TX_BUSY, &dws->dma_chan_busy) & BIT(RX_BUSY))
+       clear_bit(TX_BUSY, &dws->dma_chan_busy);
+       if (test_bit(RX_BUSY, &dws->dma_chan_busy))
                return;
        dw_spi_xfer_done(dws);
 }
@@ -156,7 +157,8 @@ static void dw_spi_dma_rx_done(void *arg)
 {
        struct dw_spi *dws = arg;
 
-       if (test_and_clear_bit(RX_BUSY, &dws->dma_chan_busy) & BIT(TX_BUSY))
+       clear_bit(RX_BUSY, &dws->dma_chan_busy);
+       if (test_bit(TX_BUSY, &dws->dma_chan_busy))
                return;
        dw_spi_xfer_done(dws);
 }
index ff9cdbd..2b2c359 100644 (file)
@@ -498,7 +498,7 @@ static int spi_qup_probe(struct platform_device *pdev)
        struct resource *res;
        struct device *dev;
        void __iomem *base;
-       u32 max_freq, iomode;
+       u32 max_freq, iomode, num_cs;
        int ret, irq, size;
 
        dev = &pdev->dev;
@@ -550,10 +550,11 @@ static int spi_qup_probe(struct platform_device *pdev)
        }
 
        /* use num-cs unless not present or out of range */
-       if (of_property_read_u16(dev->of_node, "num-cs",
-                       &master->num_chipselect) ||
-                       (master->num_chipselect > SPI_NUM_CHIPSELECTS))
+       if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) ||
+           num_cs > SPI_NUM_CHIPSELECTS)
                master->num_chipselect = SPI_NUM_CHIPSELECTS;
+       else
+               master->num_chipselect = num_cs;
 
        master->bus_num = pdev->id;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
index c64a3e5..57a1950 100644 (file)
@@ -1105,13 +1105,14 @@ void spi_finalize_current_message(struct spi_master *master)
                                "failed to unprepare message: %d\n", ret);
                }
        }
+
+       trace_spi_message_done(mesg);
+
        master->cur_msg_prepared = false;
 
        mesg->state = NULL;
        if (mesg->complete)
                mesg->complete(mesg->context);
-
-       trace_spi_message_done(mesg);
 }
 EXPORT_SYMBOL_GPL(spi_finalize_current_message);
 
index 2418302..6d5b38d 100644 (file)
@@ -38,6 +38,7 @@ config IIO_SIMPLE_DUMMY_EVENTS
 config IIO_SIMPLE_DUMMY_BUFFER
        bool "Buffered capture support"
        select IIO_BUFFER
+       select IIO_TRIGGER
        select IIO_KFIFO_BUF
        help
          Add buffered data capture to the simple dummy driver.
index fd171d8..90cc18b 100644 (file)
@@ -592,6 +592,7 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
        mutex_init(&data->lock);
 
        indio_dev->dev.parent = dev;
+       indio_dev->name = dev->driver->name;
        indio_dev->info = &hmc5843_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->channels = data->variant->channels;
index 4324282..03b2a90 100644 (file)
@@ -330,16 +330,6 @@ static void device_init_registers(struct vnt_private *pDevice)
        /* zonetype initial */
        pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
 
-       /* Get RFType */
-       pDevice->byRFType = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RFTYPE);
-
-       /* force change RevID for VT3253 emu */
-       if ((pDevice->byRFType & RF_EMU) != 0)
-                       pDevice->byRevId = 0x80;
-
-       pDevice->byRFType &= RF_MASK;
-       pr_debug("pDevice->byRFType = %x\n", pDevice->byRFType);
-
        if (!pDevice->bZoneRegExist)
                pDevice->byZoneType = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
 
@@ -1187,12 +1177,14 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        PSTxDesc head_td;
-       u32 dma_idx = TYPE_AC0DMA;
+       u32 dma_idx;
        unsigned long flags;
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       if (!ieee80211_is_data(hdr->frame_control))
+       if (ieee80211_is_data(hdr->frame_control))
+               dma_idx = TYPE_AC0DMA;
+       else
                dma_idx = TYPE_TXDMA0;
 
        if (AVAIL_TD(priv, dma_idx) < 1) {
@@ -1206,6 +1198,9 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        head_td->pTDInfo->skb = skb;
 
+       if (dma_idx == TYPE_AC0DMA)
+               head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
+
        priv->iTDUsed[dma_idx]++;
 
        /* Take ownership */
@@ -1234,13 +1229,10 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma);
 
-       if (dma_idx == TYPE_AC0DMA) {
-               head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
-
+       if (head_td->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)
                MACvTransmitAC0(priv->PortOffset);
-       } else {
+       else
                MACvTransmit0(priv->PortOffset);
-       }
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1778,6 +1770,12 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
        MACvInitialize(priv->PortOffset);
        MACvReadEtherAddress(priv->PortOffset, priv->abyCurrentNetAddr);
 
+       /* Get RFType */
+       priv->byRFType = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_RFTYPE);
+       priv->byRFType &= RF_MASK;
+
+       dev_dbg(&pcid->dev, "RF Type = %x\n", priv->byRFType);
+
        device_get_options(priv);
        device_set_options(priv);
        /* Mask out the options cannot be set to the chip */
index 941b2ad..7626f63 100644 (file)
@@ -794,6 +794,7 @@ bool RFbSetPower(
                break;
        case RATE_6M:
        case RATE_9M:
+       case RATE_12M:
        case RATE_18M:
                byPwr = priv->abyOFDMPwrTbl[uCH];
                if (priv->byRFType == RF_UW2452)
index c42cde5..c4286cc 100644 (file)
@@ -640,6 +640,7 @@ int vnt_rf_setpower(struct vnt_private *priv, u32 rate, u32 channel)
                break;
        case RATE_6M:
        case RATE_9M:
+       case RATE_12M:
        case RATE_18M:
        case RATE_24M:
        case RATE_36M:
index 50bad55..2accb6e 100644 (file)
@@ -4256,11 +4256,17 @@ int iscsit_close_connection(
        pr_debug("Closing iSCSI connection CID %hu on SID:"
                " %u\n", conn->cid, sess->sid);
        /*
-        * Always up conn_logout_comp just in case the RX Thread is sleeping
-        * and the logout response never got sent because the connection
-        * failed.
+        * Always up conn_logout_comp for the traditional TCP case just in case
+        * the RX Thread in iscsi_target_rx_opcode() is sleeping and the logout
+        * response never got sent because the connection failed.
+        *
+        * However for iser-target, isert_wait4logout() is using conn_logout_comp
+        * to signal logout response TX interrupt completion.  Go ahead and skip
+        * this for iser since isert_rx_opcode() does not wait on logout failure,
+        * and to avoid iscsi_conn pointer dereference in iser-target code.
         */
-       complete(&conn->conn_logout_comp);
+       if (conn->conn_transport->transport_type == ISCSI_TCP)
+               complete(&conn->conn_logout_comp);
 
        iscsi_release_thread_set(conn);
 
index 1c197ba..bdd8731 100644 (file)
@@ -22,7 +22,6 @@
 #include <target/target_core_fabric.h>
 
 #include <target/iscsi/iscsi_target_core.h>
-#include <target/iscsi/iscsi_transport.h>
 #include "iscsi_target_seq_pdu_list.h"
 #include "iscsi_target_tq.h"
 #include "iscsi_target_erl0.h"
@@ -940,8 +939,7 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
 
        if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
                spin_unlock_bh(&conn->state_lock);
-               if (conn->conn_transport->transport_type == ISCSI_TCP)
-                       iscsit_close_connection(conn);
+               iscsit_close_connection(conn);
                return;
        }
 
index 6b3c329..c36bd7c 100644 (file)
@@ -953,11 +953,8 @@ static int tcm_loop_make_nexus(
                transport_free_session(tl_nexus->se_sess);
                goto out;
        }
-       /*
-        * Now, register the SAS I_T Nexus as active with the call to
-        * transport_register_session()
-        */
-       __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
+       /* Now, register the SAS I_T Nexus as active. */
+       transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
                        tl_nexus->se_sess, tl_nexus);
        tl_tpg->tl_nexus = tl_nexus;
        pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated"
index 58f49ff..79b4ec3 100644 (file)
@@ -650,6 +650,18 @@ static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
        return aligned_max_sectors;
 }
 
+bool se_dev_check_wce(struct se_device *dev)
+{
+       bool wce = false;
+
+       if (dev->transport->get_write_cache)
+               wce = dev->transport->get_write_cache(dev);
+       else if (dev->dev_attrib.emulate_write_cache > 0)
+               wce = true;
+
+       return wce;
+}
+
 int se_dev_set_max_unmap_lba_count(
        struct se_device *dev,
        u32 max_unmap_lba_count)
@@ -767,6 +779,16 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
                pr_err("Illegal value %d\n", flag);
                return -EINVAL;
        }
+       if (flag &&
+           dev->transport->get_write_cache) {
+               pr_err("emulate_fua_write not supported for this device\n");
+               return -EINVAL;
+       }
+       if (dev->export_count) {
+               pr_err("emulate_fua_write cannot be changed with active"
+                      " exports: %d\n", dev->export_count);
+               return -EINVAL;
+       }
        dev->dev_attrib.emulate_fua_write = flag;
        pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n",
                        dev, dev->dev_attrib.emulate_fua_write);
@@ -801,7 +823,11 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
                pr_err("emulate_write_cache not supported for this device\n");
                return -EINVAL;
        }
-
+       if (dev->export_count) {
+               pr_err("emulate_write_cache cannot be changed with active"
+                      " exports: %d\n", dev->export_count);
+               return -EINVAL;
+       }
        dev->dev_attrib.emulate_write_cache = flag;
        pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n",
                        dev, dev->dev_attrib.emulate_write_cache);
@@ -1534,8 +1560,6 @@ int target_configure_device(struct se_device *dev)
        ret = dev->transport->configure_device(dev);
        if (ret)
                goto out;
-       dev->dev_flags |= DF_CONFIGURED;
-
        /*
         * XXX: there is not much point to have two different values here..
         */
@@ -1597,6 +1621,8 @@ int target_configure_device(struct se_device *dev)
        list_add_tail(&dev->g_dev_node, &g_device_list);
        mutex_unlock(&g_device_mutex);
 
+       dev->dev_flags |= DF_CONFIGURED;
+
        return 0;
 
 out_free_alua:
index 1045dcd..f6c954c 100644 (file)
@@ -1121,7 +1121,7 @@ static u32 pscsi_get_device_type(struct se_device *dev)
        struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
        struct scsi_device *sd = pdv->pdv_sd;
 
-       return sd->type;
+       return (sd) ? sd->type : TYPE_NO_LUN;
 }
 
 static sector_t pscsi_get_blocks(struct se_device *dev)
index 9a2f9d3..3e72974 100644 (file)
@@ -708,8 +708,7 @@ sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
                }
        }
        if (cdb[1] & 0x8) {
-               if (!dev->dev_attrib.emulate_fua_write ||
-                   !dev->dev_attrib.emulate_write_cache) {
+               if (!dev->dev_attrib.emulate_fua_write || !se_dev_check_wce(dev)) {
                        pr_err("Got CDB: 0x%02x with FUA bit set, but device"
                               " does not advertise support for FUA write\n",
                               cdb[0]);
index 460e931..6c8bd6b 100644 (file)
@@ -454,19 +454,6 @@ check_scsi_name:
 }
 EXPORT_SYMBOL(spc_emulate_evpd_83);
 
-static bool
-spc_check_dev_wce(struct se_device *dev)
-{
-       bool wce = false;
-
-       if (dev->transport->get_write_cache)
-               wce = dev->transport->get_write_cache(dev);
-       else if (dev->dev_attrib.emulate_write_cache > 0)
-               wce = true;
-
-       return wce;
-}
-
 /* Extended INQUIRY Data VPD Page */
 static sense_reason_t
 spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
@@ -490,7 +477,7 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
        buf[5] = 0x07;
 
        /* If WriteCache emulation is enabled, set V_SUP */
-       if (spc_check_dev_wce(dev))
+       if (se_dev_check_wce(dev))
                buf[6] = 0x01;
        /* If an LBA map is present set R_SUP */
        spin_lock(&cmd->se_dev->t10_alua.lba_map_lock);
@@ -897,7 +884,7 @@ static int spc_modesense_caching(struct se_cmd *cmd, u8 pc, u8 *p)
        if (pc == 1)
                goto out;
 
-       if (spc_check_dev_wce(dev))
+       if (se_dev_check_wce(dev))
                p[2] = 0x04; /* Write Cache Enable */
        p[12] = 0x20; /* Disabled Read Ahead */
 
@@ -1009,7 +996,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
             (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
                spc_modesense_write_protect(&buf[length], type);
 
-       if ((spc_check_dev_wce(dev)) &&
+       if ((se_dev_check_wce(dev)) &&
            (dev->dev_attrib.emulate_fua_write > 0))
                spc_modesense_dpofua(&buf[length], type);
 
index 0adc0f6..ac3cbab 100644 (file)
@@ -2389,6 +2389,10 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
        list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
 out:
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+       if (ret && ack_kref)
+               target_put_sess_cmd(se_sess, se_cmd);
+
        return ret;
 }
 EXPORT_SYMBOL(target_get_sess_cmd);
index 97b486c..583e755 100644 (file)
@@ -359,7 +359,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
                ep = fc_seq_exch(seq);
                if (ep) {
                        lport = ep->lp;
-                       if (lport && (ep->xid <= lport->lro_xid))
+                       if (lport && (ep->xid <= lport->lro_xid)) {
                                /*
                                 * "ddp_done" trigger invalidation of HW
                                 * specific DDP context
@@ -374,6 +374,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
                                 * identified using ep->xid)
                                 */
                                cmd->was_ddp_setup = 0;
+                       }
                }
        }
 }
index 2ab229d..6ae5b85 100644 (file)
@@ -119,7 +119,10 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
                        dw8250_force_idle(p);
                        writeb(value, p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 
@@ -163,7 +166,10 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
                        __raw_writeq(value & 0xff,
                                     p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 #endif /* CONFIG_64BIT */
@@ -187,7 +193,10 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
                        dw8250_force_idle(p);
                        writel(value, p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 
index b1893f3..3ad1458 100644 (file)
@@ -921,6 +921,9 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
        writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
                        sport->port.membase + UARTPFIFO);
 
+       /* explicitly clear RDRF */
+       readb(sport->port.membase + UARTSR1);
+
        /* flush Tx and Rx FIFO */
        writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
                        sport->port.membase + UARTCFIFO);
@@ -1076,6 +1079,8 @@ static int lpuart_startup(struct uart_port *port)
        sport->txfifo_size = 0x1 << (((temp >> UARTPFIFO_TXSIZE_OFF) &
                UARTPFIFO_FIFOSIZE_MASK) + 1);
 
+       sport->port.fifosize = sport->txfifo_size;
+
        sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) &
                UARTPFIFO_FIFOSIZE_MASK) + 1);
 
index af821a9..cf08876 100644 (file)
@@ -963,6 +963,7 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
                        free_irq(ourport->tx_irq, ourport);
                tx_enabled(port) = 0;
                ourport->tx_claimed = 0;
+               ourport->tx_mode = 0;
        }
 
        if (ourport->rx_claimed) {
index ff45104..4bfb7ac 100644 (file)
@@ -929,6 +929,13 @@ __acquires(hwep->lock)
        return retval;
 }
 
+static int otg_a_alt_hnp_support(struct ci_hdrc *ci)
+{
+       dev_warn(&ci->gadget.dev,
+               "connect the device to an alternate port if you want HNP\n");
+       return isr_setup_status_phase(ci);
+}
+
 /**
  * isr_setup_packet_handler: setup packet handler
  * @ci: UDC descriptor
@@ -1061,6 +1068,10 @@ __acquires(ci->lock)
                                                        ci);
                                }
                                break;
+                       case USB_DEVICE_A_ALT_HNP_SUPPORT:
+                               if (ci_otg_is_fsm_mode(ci))
+                                       err = otg_a_alt_hnp_support(ci);
+                               break;
                        default:
                                goto delegate;
                        }
index c6b35b7..61d538a 100644 (file)
@@ -150,9 +150,9 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
                break;
        case OTG_STATE_B_PERIPHERAL:
                otg_chrg_vbus(fsm, 0);
-               otg_loc_conn(fsm, 1);
                otg_loc_sof(fsm, 0);
                otg_set_protocol(fsm, PROTO_GADGET);
+               otg_loc_conn(fsm, 1);
                break;
        case OTG_STATE_B_WAIT_ACON:
                otg_chrg_vbus(fsm, 0);
@@ -213,10 +213,10 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 
                break;
        case OTG_STATE_A_PERIPHERAL:
-               otg_loc_conn(fsm, 1);
                otg_loc_sof(fsm, 0);
                otg_set_protocol(fsm, PROTO_GADGET);
                otg_drv_vbus(fsm, 1);
+               otg_loc_conn(fsm, 1);
                otg_add_timer(fsm, A_BIDL_ADIS);
                break;
        case OTG_STATE_A_WAIT_VFALL:
index 02e3e2d..6cf0478 100644 (file)
@@ -377,6 +377,9 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
                dwc2_is_host_mode(hsotg) ? "Host" : "Device",
                dwc2_op_state_str(hsotg));
 
+       if (hsotg->op_state == OTG_STATE_A_HOST)
+               dwc2_hcd_disconnect(hsotg);
+
        /* Change to L3 (OFF) state */
        hsotg->lx_state = DWC2_L3;
 
index 298b461..39f49f1 100644 (file)
@@ -289,8 +289,7 @@ static void disable_loopback(struct f_loopback *loop)
        struct usb_composite_dev        *cdev;
 
        cdev = loop->function.config->cdev;
-       disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL, NULL,
-                       NULL);
+       disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
        VDBG(cdev, "%s disabled\n", loop->function.name);
 }
 
index e3dae47..3a5ae99 100644 (file)
 #include "gadget_chips.h"
 #include "u_f.h"
 
-#define USB_MS_TO_SS_INTERVAL(x) USB_MS_TO_HS_INTERVAL(x)
-
-enum eptype {
-       EP_CONTROL = 0,
-       EP_BULK,
-       EP_ISOC,
-       EP_INTERRUPT,
-};
-
 /*
  * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
  * controller drivers.
@@ -64,8 +55,6 @@ struct f_sourcesink {
        struct usb_ep           *out_ep;
        struct usb_ep           *iso_in_ep;
        struct usb_ep           *iso_out_ep;
-       struct usb_ep           *int_in_ep;
-       struct usb_ep           *int_out_ep;
        int                     cur_alt;
 };
 
@@ -79,10 +68,6 @@ static unsigned isoc_interval;
 static unsigned isoc_maxpacket;
 static unsigned isoc_mult;
 static unsigned isoc_maxburst;
-static unsigned int_interval; /* In ms */
-static unsigned int_maxpacket;
-static unsigned int_mult;
-static unsigned int_maxburst;
 static unsigned buflen;
 
 /*-------------------------------------------------------------------------*/
@@ -107,16 +92,6 @@ static struct usb_interface_descriptor source_sink_intf_alt1 = {
        /* .iInterface          = DYNAMIC */
 };
 
-static struct usb_interface_descriptor source_sink_intf_alt2 = {
-       .bLength =              USB_DT_INTERFACE_SIZE,
-       .bDescriptorType =      USB_DT_INTERFACE,
-
-       .bAlternateSetting =    2,
-       .bNumEndpoints =        2,
-       .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
-       /* .iInterface          = DYNAMIC */
-};
-
 /* full speed support: */
 
 static struct usb_endpoint_descriptor fs_source_desc = {
@@ -155,26 +130,6 @@ static struct usb_endpoint_descriptor fs_iso_sink_desc = {
        .bInterval =            4,
 };
 
-static struct usb_endpoint_descriptor fs_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(64),
-       .bInterval =            GZERO_INT_INTERVAL,
-};
-
-static struct usb_endpoint_descriptor fs_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(64),
-       .bInterval =            GZERO_INT_INTERVAL,
-};
-
 static struct usb_descriptor_header *fs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &fs_sink_desc,
@@ -185,10 +140,6 @@ static struct usb_descriptor_header *fs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &fs_source_desc,
        (struct usb_descriptor_header *) &fs_iso_sink_desc,
        (struct usb_descriptor_header *) &fs_iso_source_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define FS_ALT_IFC_2_OFFSET    8
-       (struct usb_descriptor_header *) &fs_int_sink_desc,
-       (struct usb_descriptor_header *) &fs_int_source_desc,
        NULL,
 };
 
@@ -228,24 +179,6 @@ static struct usb_endpoint_descriptor hs_iso_sink_desc = {
        .bInterval =            4,
 };
 
-static struct usb_endpoint_descriptor hs_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-static struct usb_endpoint_descriptor hs_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
 static struct usb_descriptor_header *hs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &hs_source_desc,
@@ -256,10 +189,6 @@ static struct usb_descriptor_header *hs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &hs_sink_desc,
        (struct usb_descriptor_header *) &hs_iso_source_desc,
        (struct usb_descriptor_header *) &hs_iso_sink_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define HS_ALT_IFC_2_OFFSET    8
-       (struct usb_descriptor_header *) &hs_int_source_desc,
-       (struct usb_descriptor_header *) &hs_int_sink_desc,
        NULL,
 };
 
@@ -335,42 +264,6 @@ static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
        .wBytesPerInterval =    cpu_to_le16(1024),
 };
 
-static struct usb_endpoint_descriptor ss_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-static struct usb_ss_ep_comp_descriptor ss_int_source_comp_desc = {
-       .bLength =              USB_DT_SS_EP_COMP_SIZE,
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-
-       .bMaxBurst =            0,
-       .bmAttributes =         0,
-       .wBytesPerInterval =    cpu_to_le16(1024),
-};
-
-static struct usb_endpoint_descriptor ss_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-static struct usb_ss_ep_comp_descriptor ss_int_sink_comp_desc = {
-       .bLength =              USB_DT_SS_EP_COMP_SIZE,
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-
-       .bMaxBurst =            0,
-       .bmAttributes =         0,
-       .wBytesPerInterval =    cpu_to_le16(1024),
-};
-
 static struct usb_descriptor_header *ss_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &ss_source_desc,
@@ -387,12 +280,6 @@ static struct usb_descriptor_header *ss_source_sink_descs[] = {
        (struct usb_descriptor_header *) &ss_iso_source_comp_desc,
        (struct usb_descriptor_header *) &ss_iso_sink_desc,
        (struct usb_descriptor_header *) &ss_iso_sink_comp_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define SS_ALT_IFC_2_OFFSET    14
-       (struct usb_descriptor_header *) &ss_int_source_desc,
-       (struct usb_descriptor_header *) &ss_int_source_comp_desc,
-       (struct usb_descriptor_header *) &ss_int_sink_desc,
-       (struct usb_descriptor_header *) &ss_int_sink_comp_desc,
        NULL,
 };
 
@@ -414,21 +301,6 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
 };
 
 /*-------------------------------------------------------------------------*/
-static const char *get_ep_string(enum eptype ep_type)
-{
-       switch (ep_type) {
-       case EP_ISOC:
-               return "ISOC-";
-       case EP_INTERRUPT:
-               return "INTERRUPT-";
-       case EP_CONTROL:
-               return "CTRL-";
-       case EP_BULK:
-               return "BULK-";
-       default:
-               return "UNKNOWN-";
-       }
-}
 
 static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
 {
@@ -456,8 +328,7 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
 
 void disable_endpoints(struct usb_composite_dev *cdev,
                struct usb_ep *in, struct usb_ep *out,
-               struct usb_ep *iso_in, struct usb_ep *iso_out,
-               struct usb_ep *int_in, struct usb_ep *int_out)
+               struct usb_ep *iso_in, struct usb_ep *iso_out)
 {
        disable_ep(cdev, in);
        disable_ep(cdev, out);
@@ -465,10 +336,6 @@ void disable_endpoints(struct usb_composite_dev *cdev,
                disable_ep(cdev, iso_in);
        if (iso_out)
                disable_ep(cdev, iso_out);
-       if (int_in)
-               disable_ep(cdev, int_in);
-       if (int_out)
-               disable_ep(cdev, int_out);
 }
 
 static int
@@ -485,7 +352,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
                return id;
        source_sink_intf_alt0.bInterfaceNumber = id;
        source_sink_intf_alt1.bInterfaceNumber = id;
-       source_sink_intf_alt2.bInterfaceNumber = id;
 
        /* allocate bulk endpoints */
        ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
@@ -546,55 +412,14 @@ no_iso:
        if (isoc_maxpacket > 1024)
                isoc_maxpacket = 1024;
 
-       /* sanity check the interrupt module parameters */
-       if (int_interval < 1)
-               int_interval = 1;
-       if (int_interval > 4096)
-               int_interval = 4096;
-       if (int_mult > 2)
-               int_mult = 2;
-       if (int_maxburst > 15)
-               int_maxburst = 15;
-
-       /* fill in the FS interrupt descriptors from the module parameters */
-       fs_int_source_desc.wMaxPacketSize = int_maxpacket > 64 ?
-                                               64 : int_maxpacket;
-       fs_int_source_desc.bInterval = int_interval > 255 ?
-                                               255 : int_interval;
-       fs_int_sink_desc.wMaxPacketSize = int_maxpacket > 64 ?
-                                               64 : int_maxpacket;
-       fs_int_sink_desc.bInterval = int_interval > 255 ?
-                                               255 : int_interval;
-
-       /* allocate int endpoints */
-       ss->int_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_source_desc);
-       if (!ss->int_in_ep)
-               goto no_int;
-       ss->int_in_ep->driver_data = cdev;      /* claim */
-
-       ss->int_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_sink_desc);
-       if (ss->int_out_ep) {
-               ss->int_out_ep->driver_data = cdev;     /* claim */
-       } else {
-               ss->int_in_ep->driver_data = NULL;
-               ss->int_in_ep = NULL;
-no_int:
-               fs_source_sink_descs[FS_ALT_IFC_2_OFFSET] = NULL;
-               hs_source_sink_descs[HS_ALT_IFC_2_OFFSET] = NULL;
-               ss_source_sink_descs[SS_ALT_IFC_2_OFFSET] = NULL;
-       }
-
-       if (int_maxpacket > 1024)
-               int_maxpacket = 1024;
-
        /* support high speed hardware */
        hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
        hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 
        /*
-        * Fill in the HS isoc and interrupt descriptors from the module
-        * parameters. We assume that the user knows what they are doing and
-        * won't give parameters that their UDC doesn't support.
+        * Fill in the HS isoc descriptors from the module parameters.
+        * We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
         */
        hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
        hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
@@ -607,17 +432,6 @@ no_int:
        hs_iso_sink_desc.bInterval = isoc_interval;
        hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
 
-       hs_int_source_desc.wMaxPacketSize = int_maxpacket;
-       hs_int_source_desc.wMaxPacketSize |= int_mult << 11;
-       hs_int_source_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval);
-       hs_int_source_desc.bEndpointAddress =
-               fs_int_source_desc.bEndpointAddress;
-
-       hs_int_sink_desc.wMaxPacketSize = int_maxpacket;
-       hs_int_sink_desc.wMaxPacketSize |= int_mult << 11;
-       hs_int_sink_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval);
-       hs_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress;
-
        /* support super speed hardware */
        ss_source_desc.bEndpointAddress =
                fs_source_desc.bEndpointAddress;
@@ -625,9 +439,9 @@ no_int:
                fs_sink_desc.bEndpointAddress;
 
        /*
-        * Fill in the SS isoc and interrupt descriptors from the module
-        * parameters. We assume that the user knows what they are doing and
-        * won't give parameters that their UDC doesn't support.
+        * Fill in the SS isoc descriptors from the module parameters.
+        * We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
         */
        ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
        ss_iso_source_desc.bInterval = isoc_interval;
@@ -646,37 +460,17 @@ no_int:
                isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
        ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
 
-       ss_int_source_desc.wMaxPacketSize = int_maxpacket;
-       ss_int_source_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval);
-       ss_int_source_comp_desc.bmAttributes = int_mult;
-       ss_int_source_comp_desc.bMaxBurst = int_maxburst;
-       ss_int_source_comp_desc.wBytesPerInterval =
-               int_maxpacket * (int_mult + 1) * (int_maxburst + 1);
-       ss_int_source_desc.bEndpointAddress =
-               fs_int_source_desc.bEndpointAddress;
-
-       ss_int_sink_desc.wMaxPacketSize = int_maxpacket;
-       ss_int_sink_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval);
-       ss_int_sink_comp_desc.bmAttributes = int_mult;
-       ss_int_sink_comp_desc.bMaxBurst = int_maxburst;
-       ss_int_sink_comp_desc.wBytesPerInterval =
-               int_maxpacket * (int_mult + 1) * (int_maxburst + 1);
-       ss_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress;
-
        ret = usb_assign_descriptors(f, fs_source_sink_descs,
                        hs_source_sink_descs, ss_source_sink_descs);
        if (ret)
                return ret;
 
-       DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s, "
-                       "INT-IN/%s, INT-OUT/%s\n",
+       DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
            (gadget_is_superspeed(c->cdev->gadget) ? "super" :
             (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
                        f->name, ss->in_ep->name, ss->out_ep->name,
                        ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
-                       ss->iso_out_ep ? ss->iso_out_ep->name : "<none>",
-                       ss->int_in_ep ? ss->int_in_ep->name : "<none>",
-                       ss->int_out_ep ? ss->int_out_ep->name : "<none>");
+                       ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
        return 0;
 }
 
@@ -807,15 +601,14 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
 }
 
 static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
-               enum eptype ep_type, int speed)
+               bool is_iso, int speed)
 {
        struct usb_ep           *ep;
        struct usb_request      *req;
        int                     i, size, status;
 
        for (i = 0; i < 8; i++) {
-               switch (ep_type) {
-               case EP_ISOC:
+               if (is_iso) {
                        switch (speed) {
                        case USB_SPEED_SUPER:
                                size = isoc_maxpacket * (isoc_mult + 1) *
@@ -831,28 +624,9 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
                        }
                        ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
                        req = ss_alloc_ep_req(ep, size);
-                       break;
-               case EP_INTERRUPT:
-                       switch (speed) {
-                       case USB_SPEED_SUPER:
-                               size = int_maxpacket * (int_mult + 1) *
-                                               (int_maxburst + 1);
-                               break;
-                       case USB_SPEED_HIGH:
-                               size = int_maxpacket * (int_mult + 1);
-                               break;
-                       default:
-                               size = int_maxpacket > 1023 ?
-                                               1023 : int_maxpacket;
-                               break;
-                       }
-                       ep = is_in ? ss->int_in_ep : ss->int_out_ep;
-                       req = ss_alloc_ep_req(ep, size);
-                       break;
-               default:
+               } else {
                        ep = is_in ? ss->in_ep : ss->out_ep;
                        req = ss_alloc_ep_req(ep, 0);
-                       break;
                }
 
                if (!req)
@@ -870,12 +644,12 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 
                        cdev = ss->function.config->cdev;
                        ERROR(cdev, "start %s%s %s --> %d\n",
-                               get_ep_string(ep_type), is_in ? "IN" : "OUT",
-                               ep->name, status);
+                             is_iso ? "ISO-" : "", is_in ? "IN" : "OUT",
+                             ep->name, status);
                        free_ep_req(ep, req);
                }
 
-               if (!(ep_type == EP_ISOC))
+               if (!is_iso)
                        break;
        }
 
@@ -888,7 +662,7 @@ static void disable_source_sink(struct f_sourcesink *ss)
 
        cdev = ss->function.config->cdev;
        disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep,
-                       ss->iso_out_ep, ss->int_in_ep, ss->int_out_ep);
+                       ss->iso_out_ep);
        VDBG(cdev, "%s disabled\n", ss->function.name);
 }
 
@@ -900,62 +674,6 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
        int                                     speed = cdev->gadget->speed;
        struct usb_ep                           *ep;
 
-       if (alt == 2) {
-               /* Configure for periodic interrupt endpoint */
-               ep = ss->int_in_ep;
-               if (ep) {
-                       result = config_ep_by_speed(cdev->gadget,
-                                       &(ss->function), ep);
-                       if (result)
-                               return result;
-
-                       result = usb_ep_enable(ep);
-                       if (result < 0)
-                               return result;
-
-                       ep->driver_data = ss;
-                       result = source_sink_start_ep(ss, true, EP_INTERRUPT,
-                                       speed);
-                       if (result < 0) {
-fail1:
-                               ep = ss->int_in_ep;
-                               if (ep) {
-                                       usb_ep_disable(ep);
-                                       ep->driver_data = NULL;
-                               }
-                               return result;
-                       }
-               }
-
-               /*
-                * one interrupt endpoint reads (sinks) anything OUT (from the
-                * host)
-                */
-               ep = ss->int_out_ep;
-               if (ep) {
-                       result = config_ep_by_speed(cdev->gadget,
-                                       &(ss->function), ep);
-                       if (result)
-                               goto fail1;
-
-                       result = usb_ep_enable(ep);
-                       if (result < 0)
-                               goto fail1;
-
-                       ep->driver_data = ss;
-                       result = source_sink_start_ep(ss, false, EP_INTERRUPT,
-                                       speed);
-                       if (result < 0) {
-                               ep = ss->int_out_ep;
-                               usb_ep_disable(ep);
-                               ep->driver_data = NULL;
-                               goto fail1;
-                       }
-               }
-
-               goto out;
-       }
-
        /* one bulk endpoint writes (sources) zeroes IN (to the host) */
        ep = ss->in_ep;
        result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
@@ -966,7 +684,7 @@ fail1:
                return result;
        ep->driver_data = ss;
 
-       result = source_sink_start_ep(ss, true, EP_BULK, speed);
+       result = source_sink_start_ep(ss, true, false, speed);
        if (result < 0) {
 fail:
                ep = ss->in_ep;
@@ -985,7 +703,7 @@ fail:
                goto fail;
        ep->driver_data = ss;
 
-       result = source_sink_start_ep(ss, false, EP_BULK, speed);
+       result = source_sink_start_ep(ss, false, false, speed);
        if (result < 0) {
 fail2:
                ep = ss->out_ep;
@@ -1008,7 +726,7 @@ fail2:
                        goto fail2;
                ep->driver_data = ss;
 
-               result = source_sink_start_ep(ss, true, EP_ISOC, speed);
+               result = source_sink_start_ep(ss, true, true, speed);
                if (result < 0) {
 fail3:
                        ep = ss->iso_in_ep;
@@ -1031,14 +749,13 @@ fail3:
                        goto fail3;
                ep->driver_data = ss;
 
-               result = source_sink_start_ep(ss, false, EP_ISOC, speed);
+               result = source_sink_start_ep(ss, false, true, speed);
                if (result < 0) {
                        usb_ep_disable(ep);
                        ep->driver_data = NULL;
                        goto fail3;
                }
        }
-
 out:
        ss->cur_alt = alt;
 
@@ -1054,8 +771,6 @@ static int sourcesink_set_alt(struct usb_function *f,
 
        if (ss->in_ep->driver_data)
                disable_source_sink(ss);
-       else if (alt == 2 && ss->int_in_ep->driver_data)
-               disable_source_sink(ss);
        return enable_source_sink(cdev, ss, alt);
 }
 
@@ -1168,10 +883,6 @@ static struct usb_function *source_sink_alloc_func(
        isoc_maxpacket = ss_opts->isoc_maxpacket;
        isoc_mult = ss_opts->isoc_mult;
        isoc_maxburst = ss_opts->isoc_maxburst;
-       int_interval = ss_opts->int_interval;
-       int_maxpacket = ss_opts->int_maxpacket;
-       int_mult = ss_opts->int_mult;
-       int_maxburst = ss_opts->int_maxburst;
        buflen = ss_opts->bulk_buflen;
 
        ss->function.name = "source/sink";
@@ -1468,182 +1179,6 @@ static struct f_ss_opts_attribute f_ss_opts_bulk_buflen =
                        f_ss_opts_bulk_buflen_show,
                        f_ss_opts_bulk_buflen_store);
 
-static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_interval);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_interval_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u32 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou32(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 4096) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_interval = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_interval =
-       __CONFIGFS_ATTR(int_interval, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_interval_show,
-                       f_ss_opts_int_interval_store);
-
-static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_maxpacket);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_maxpacket_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u16 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou16(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 1024) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_maxpacket = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_maxpacket =
-       __CONFIGFS_ATTR(int_maxpacket, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_maxpacket_show,
-                       f_ss_opts_int_maxpacket_store);
-
-static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_mult);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_mult_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u8 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou8(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 2) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_mult = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_mult =
-       __CONFIGFS_ATTR(int_mult, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_mult_show,
-                       f_ss_opts_int_mult_store);
-
-static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_maxburst);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_maxburst_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u8 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou8(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 15) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_maxburst = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_maxburst =
-       __CONFIGFS_ATTR(int_maxburst, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_maxburst_show,
-                       f_ss_opts_int_maxburst_store);
-
 static struct configfs_attribute *ss_attrs[] = {
        &f_ss_opts_pattern.attr,
        &f_ss_opts_isoc_interval.attr,
@@ -1651,10 +1186,6 @@ static struct configfs_attribute *ss_attrs[] = {
        &f_ss_opts_isoc_mult.attr,
        &f_ss_opts_isoc_maxburst.attr,
        &f_ss_opts_bulk_buflen.attr,
-       &f_ss_opts_int_interval.attr,
-       &f_ss_opts_int_maxpacket.attr,
-       &f_ss_opts_int_mult.attr,
-       &f_ss_opts_int_maxburst.attr,
        NULL,
 };
 
@@ -1684,8 +1215,6 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
        ss_opts->isoc_interval = GZERO_ISOC_INTERVAL;
        ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET;
        ss_opts->bulk_buflen = GZERO_BULK_BUFLEN;
-       ss_opts->int_interval = GZERO_INT_INTERVAL;
-       ss_opts->int_maxpacket = GZERO_INT_MAXPACKET;
 
        config_group_init_type_name(&ss_opts->func_inst.group, "",
                                    &ss_func_type);
index 2ce28b9..15f1809 100644 (file)
@@ -10,8 +10,6 @@
 #define GZERO_QLEN             32
 #define GZERO_ISOC_INTERVAL    4
 #define GZERO_ISOC_MAXPACKET   1024
-#define GZERO_INT_INTERVAL     1 /* Default interrupt interval = 1 ms */
-#define GZERO_INT_MAXPACKET    1024
 
 struct usb_zero_options {
        unsigned pattern;
@@ -19,10 +17,6 @@ struct usb_zero_options {
        unsigned isoc_maxpacket;
        unsigned isoc_mult;
        unsigned isoc_maxburst;
-       unsigned int_interval; /* In ms */
-       unsigned int_maxpacket;
-       unsigned int_mult;
-       unsigned int_maxburst;
        unsigned bulk_buflen;
        unsigned qlen;
 };
@@ -34,10 +28,6 @@ struct f_ss_opts {
        unsigned isoc_maxpacket;
        unsigned isoc_mult;
        unsigned isoc_maxburst;
-       unsigned int_interval; /* In ms */
-       unsigned int_maxpacket;
-       unsigned int_mult;
-       unsigned int_maxburst;
        unsigned bulk_buflen;
 
        /*
@@ -72,7 +62,6 @@ int lb_modinit(void);
 void free_ep_req(struct usb_ep *ep, struct usb_request *req);
 void disable_endpoints(struct usb_composite_dev *cdev,
                struct usb_ep *in, struct usb_ep *out,
-               struct usb_ep *iso_in, struct usb_ep *iso_out,
-               struct usb_ep *int_in, struct usb_ep *int_out);
+               struct usb_ep *iso_in, struct usb_ep *iso_out);
 
 #endif /* __G_ZERO_H */
index 3a49416..6e0a019 100644 (file)
@@ -1740,10 +1740,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
                goto err_session;
        }
        /*
-        * Now register the TCM vHost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
+        * Now register the TCM vHost virtual I_T Nexus as active.
         */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
        mutex_unlock(&tpg->tpg_mutex);
index ff97ac9..5ee9515 100644 (file)
@@ -68,8 +68,6 @@ static struct usb_zero_options gzero_options = {
        .isoc_maxpacket = GZERO_ISOC_MAXPACKET,
        .bulk_buflen = GZERO_BULK_BUFLEN,
        .qlen = GZERO_QLEN,
-       .int_interval = GZERO_INT_INTERVAL,
-       .int_maxpacket = GZERO_INT_MAXPACKET,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -268,21 +266,6 @@ module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint,
                S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
 
-module_param_named(int_interval, gzero_options.int_interval, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_interval, "1 - 16");
-
-module_param_named(int_maxpacket, gzero_options.int_maxpacket, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
-
-module_param_named(int_mult, gzero_options.int_mult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_mult, "0 - 2 (hs/ss only)");
-
-module_param_named(int_maxburst, gzero_options.int_maxburst, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_maxburst, "0 - 15 (ss only)");
-
 static struct usb_function *func_lb;
 static struct usb_function_instance *func_inst_lb;
 
@@ -318,10 +301,6 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
        ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;
        ss_opts->isoc_mult = gzero_options.isoc_mult;
        ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
-       ss_opts->int_interval = gzero_options.int_interval;
-       ss_opts->int_maxpacket = gzero_options.int_maxpacket;
-       ss_opts->int_mult = gzero_options.int_mult;
-       ss_opts->int_maxburst = gzero_options.int_maxburst;
        ss_opts->bulk_buflen = gzero_options.bulk_buflen;
 
        func_ss = usb_get_function(func_inst_ss);
index 663f790..be0964a 100644 (file)
@@ -34,7 +34,6 @@ static const char hcd_name[] = "ehci-atmel";
 
 struct atmel_ehci_priv {
        struct clk *iclk;
-       struct clk *fclk;
        struct clk *uclk;
        bool clocked;
 };
@@ -51,12 +50,9 @@ static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 {
        if (atmel_ehci->clocked)
                return;
-       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-               clk_set_rate(atmel_ehci->uclk, 48000000);
-               clk_prepare_enable(atmel_ehci->uclk);
-       }
+
+       clk_prepare_enable(atmel_ehci->uclk);
        clk_prepare_enable(atmel_ehci->iclk);
-       clk_prepare_enable(atmel_ehci->fclk);
        atmel_ehci->clocked = true;
 }
 
@@ -64,10 +60,9 @@ static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 {
        if (!atmel_ehci->clocked)
                return;
-       clk_disable_unprepare(atmel_ehci->fclk);
+
        clk_disable_unprepare(atmel_ehci->iclk);
-       if (IS_ENABLED(CONFIG_COMMON_CLK))
-               clk_disable_unprepare(atmel_ehci->uclk);
+       clk_disable_unprepare(atmel_ehci->uclk);
        atmel_ehci->clocked = false;
 }
 
@@ -146,20 +141,13 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
                retval = -ENOENT;
                goto fail_request_resource;
        }
-       atmel_ehci->fclk = devm_clk_get(&pdev->dev, "uhpck");
-       if (IS_ERR(atmel_ehci->fclk)) {
-               dev_err(&pdev->dev, "Error getting function clock\n");
-               retval = -ENOENT;
+
+       atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
+       if (IS_ERR(atmel_ehci->uclk)) {
+               dev_err(&pdev->dev, "failed to get uclk\n");
+               retval = PTR_ERR(atmel_ehci->uclk);
                goto fail_request_resource;
        }
-       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-               atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
-               if (IS_ERR(atmel_ehci->uclk)) {
-                       dev_err(&pdev->dev, "failed to get uclk\n");
-                       retval = PTR_ERR(atmel_ehci->uclk);
-                       goto fail_request_resource;
-               }
-       }
 
        ehci = hcd_to_ehci(hcd);
        /* registers start at offset 0x0 */
index a7865c4..0827d7c 100644 (file)
@@ -387,6 +387,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
                status = PORT_PLC;
                port_change_bit = "link state";
                break;
+       case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
+               status = PORT_CEC;
+               port_change_bit = "config error";
+               break;
        default:
                /* Should never happen */
                return;
@@ -588,6 +592,8 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                        status |= USB_PORT_STAT_C_LINK_STATE << 16;
                if ((raw_port_status & PORT_WRC))
                        status |= USB_PORT_STAT_C_BH_RESET << 16;
+               if ((raw_port_status & PORT_CEC))
+                       status |= USB_PORT_STAT_C_CONFIG_ERROR << 16;
        }
 
        if (hcd->speed != HCD_USB3) {
@@ -1005,6 +1011,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                case USB_PORT_FEAT_C_OVER_CURRENT:
                case USB_PORT_FEAT_C_ENABLE:
                case USB_PORT_FEAT_C_PORT_LINK_STATE:
+               case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
                        xhci_clear_port_change_bit(xhci, wValue, wIndex,
                                        port_array[wIndex], temp);
                        break;
@@ -1069,7 +1076,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
         */
        status = bus_state->resuming_ports;
 
-       mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
+       mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC;
 
        spin_lock_irqsave(&xhci->lock, flags);
        /* For each port, did anything change?  If so, set that bit in buf. */
index fd53c9e..2af32e2 100644 (file)
@@ -115,6 +115,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
                xhci->quirks |= XHCI_LPM_SUPPORT;
                xhci->quirks |= XHCI_INTEL_HOST;
+               xhci->quirks |= XHCI_AVOID_BEI;
        }
        if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
                        pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
@@ -130,7 +131,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                 * PPT chipsets.
                 */
                xhci->quirks |= XHCI_SPURIOUS_REBOOT;
-               xhci->quirks |= XHCI_AVOID_BEI;
        }
        if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
                pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) {
index 5fb66db..73485fa 100644 (file)
@@ -1729,7 +1729,7 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
        if (!command)
                return;
 
-       ep->ep_state |= EP_HALTED | EP_RECENTLY_HALTED;
+       ep->ep_state |= EP_HALTED;
        ep->stopped_stream = stream_id;
 
        xhci_queue_reset_ep(xhci, command, slot_id, ep_index);
index b06d1a5..ec8ac16 100644 (file)
@@ -1338,12 +1338,6 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
                goto exit;
        }
 
-       /* Reject urb if endpoint is in soft reset, queue must stay empty */
-       if (xhci->devs[slot_id]->eps[ep_index].ep_state & EP_CONFIG_PENDING) {
-               xhci_warn(xhci, "Can't enqueue URB while ep is in soft reset\n");
-               ret = -EINVAL;
-       }
-
        if (usb_endpoint_xfer_isoc(&urb->ep->desc))
                size = urb->number_of_packets;
        else
@@ -2954,36 +2948,23 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
        }
 }
 
-/* Called after clearing a halted device. USB core should have sent the control
+/* Called when clearing halted device. The core should have sent the control
  * message to clear the device halt condition. The host side of the halt should
- * already be cleared with a reset endpoint command issued immediately when the
- * STALL tx event was received.
+ * already be cleared with a reset endpoint command issued when the STALL tx
+ * event was received.
+ *
+ * Context: in_interrupt
  */
 
 void xhci_endpoint_reset(struct usb_hcd *hcd,
                struct usb_host_endpoint *ep)
 {
        struct xhci_hcd *xhci;
-       struct usb_device *udev;
-       struct xhci_virt_device *virt_dev;
-       struct xhci_virt_ep *virt_ep;
-       struct xhci_input_control_ctx *ctrl_ctx;
-       struct xhci_command *command;
-       unsigned int ep_index, ep_state;
-       unsigned long flags;
-       u32 ep_flag;
 
        xhci = hcd_to_xhci(hcd);
-       udev = (struct usb_device *) ep->hcpriv;
-       if (!ep->hcpriv)
-               return;
-       virt_dev = xhci->devs[udev->slot_id];
-       ep_index = xhci_get_endpoint_index(&ep->desc);
-       virt_ep = &virt_dev->eps[ep_index];
-       ep_state = virt_ep->ep_state;
 
        /*
-        * Implement the config ep command in xhci 4.6.8 additional note:
+        * We might need to implement the config ep cmd in xhci 4.8.1 note:
         * The Reset Endpoint Command may only be issued to endpoints in the
         * Halted state. If software wishes reset the Data Toggle or Sequence
         * Number of an endpoint that isn't in the Halted state, then software
@@ -2991,72 +2972,9 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
         * for the target endpoint. that is in the Stopped state.
         */
 
-       if (ep_state & SET_DEQ_PENDING || ep_state & EP_RECENTLY_HALTED) {
-               virt_ep->ep_state &= ~EP_RECENTLY_HALTED;
-               xhci_dbg(xhci, "ep recently halted, no toggle reset needed\n");
-               return;
-       }
-
-       /* Only interrupt and bulk ep's use Data toggle, USB2 spec 5.5.4-> */
-       if (usb_endpoint_xfer_control(&ep->desc) ||
-           usb_endpoint_xfer_isoc(&ep->desc))
-               return;
-
-       ep_flag = xhci_get_endpoint_flag(&ep->desc);
-
-       if (ep_flag == SLOT_FLAG || ep_flag == EP0_FLAG)
-               return;
-
-       command = xhci_alloc_command(xhci, true, true, GFP_NOWAIT);
-       if (!command) {
-               xhci_err(xhci, "Could not allocate xHCI command structure.\n");
-               return;
-       }
-
-       spin_lock_irqsave(&xhci->lock, flags);
-
-       /* block ringing ep doorbell */
-       virt_ep->ep_state |= EP_CONFIG_PENDING;
-
-       /*
-        * Make sure endpoint ring is empty before resetting the toggle/seq.
-        * Driver is required to synchronously cancel all transfer request.
-        *
-        * xhci 4.6.6 says we can issue a configure endpoint command on a
-        * running endpoint ring as long as it's idle (queue empty)
-        */
-
-       if (!list_empty(&virt_ep->ring->td_list)) {
-               dev_err(&udev->dev, "EP not empty, refuse reset\n");
-               spin_unlock_irqrestore(&xhci->lock, flags);
-               goto cleanup;
-       }
-
-       xhci_dbg(xhci, "Reset toggle/seq for slot %d, ep_index: %d\n",
-                udev->slot_id, ep_index);
-
-       ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
-       if (!ctrl_ctx) {
-               xhci_err(xhci, "Could not get input context, bad type. virt_dev: %p, in_ctx %p\n",
-                        virt_dev, virt_dev->in_ctx);
-               spin_unlock_irqrestore(&xhci->lock, flags);
-               goto cleanup;
-       }
-       xhci_setup_input_ctx_for_config_ep(xhci, command->in_ctx,
-                                          virt_dev->out_ctx, ctrl_ctx,
-                                          ep_flag, ep_flag);
-       xhci_endpoint_copy(xhci, command->in_ctx, virt_dev->out_ctx, ep_index);
-
-       xhci_queue_configure_endpoint(xhci, command, command->in_ctx->dma,
-                                    udev->slot_id, false);
-       xhci_ring_cmd_db(xhci);
-       spin_unlock_irqrestore(&xhci->lock, flags);
-
-       wait_for_completion(command->completion);
-
-cleanup:
-       virt_ep->ep_state &= ~EP_CONFIG_PENDING;
-       xhci_free_command(xhci, command);
+       /* For now just print debug to follow the situation */
+       xhci_dbg(xhci, "Endpoint 0x%x ep reset callback called\n",
+                ep->desc.bEndpointAddress);
 }
 
 static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
index 265ab17..8e421b8 100644 (file)
@@ -865,8 +865,6 @@ struct xhci_virt_ep {
 #define EP_HAS_STREAMS         (1 << 4)
 /* Transitioning the endpoint to not using streams, don't enqueue URBs */
 #define EP_GETTING_NO_STREAMS  (1 << 5)
-#define EP_RECENTLY_HALTED     (1 << 6)
-#define EP_CONFIG_PENDING      (1 << 7)
        /* ----  Related to URB cancellation ---- */
        struct list_head        cancelled_td_list;
        struct xhci_td          *stopped_td;
index b982755..bfa402c 100644 (file)
@@ -151,8 +151,7 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
        }
 
        if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
-               ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED |
-                                          IRQF_DISABLED);
+               ret = isp1760_udc_register(isp, irq, irqflags);
                if (ret < 0) {
                        isp1760_hcd_unregister(&isp->hcd);
                        return ret;
index 9612d79..3fc4fe7 100644 (file)
@@ -1191,6 +1191,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
                             struct usb_gadget_driver *driver)
 {
        struct isp1760_udc *udc = gadget_to_udc(gadget);
+       unsigned long flags;
 
        /* The hardware doesn't support low speed. */
        if (driver->max_speed < USB_SPEED_FULL) {
@@ -1198,17 +1199,17 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
                return -EINVAL;
        }
 
-       spin_lock(&udc->lock);
+       spin_lock_irqsave(&udc->lock, flags);
 
        if (udc->driver) {
                dev_err(udc->isp->dev, "UDC already has a gadget driver\n");
-               spin_unlock(&udc->lock);
+               spin_unlock_irqrestore(&udc->lock, flags);
                return -EBUSY;
        }
 
        udc->driver = driver;
 
-       spin_unlock(&udc->lock);
+       spin_unlock_irqrestore(&udc->lock, flags);
 
        dev_dbg(udc->isp->dev, "starting UDC with driver %s\n",
                driver->function);
@@ -1232,6 +1233,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
 static int isp1760_udc_stop(struct usb_gadget *gadget)
 {
        struct isp1760_udc *udc = gadget_to_udc(gadget);
+       unsigned long flags;
 
        dev_dbg(udc->isp->dev, "%s\n", __func__);
 
@@ -1239,9 +1241,9 @@ static int isp1760_udc_stop(struct usb_gadget *gadget)
 
        isp1760_udc_write(udc, DC_MODE, 0);
 
-       spin_lock(&udc->lock);
+       spin_lock_irqsave(&udc->lock, flags);
        udc->driver = NULL;
-       spin_unlock(&udc->lock);
+       spin_unlock_irqrestore(&udc->lock, flags);
 
        return 0;
 }
@@ -1411,7 +1413,7 @@ static int isp1760_udc_init(struct isp1760_udc *udc)
                return -ENODEV;
        }
 
-       if (chipid != 0x00011582) {
+       if (chipid != 0x00011582 && chipid != 0x00158210) {
                dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid);
                return -ENODEV;
        }
@@ -1451,8 +1453,8 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq,
 
        sprintf(udc->irqname, "%s (udc)", devname);
 
-       ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | IRQF_DISABLED |
-                         irqflags, udc->irqname, udc);
+       ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | irqflags,
+                         udc->irqname, udc);
        if (ret < 0)
                goto error;
 
index 14e1628..39db8b6 100644 (file)
@@ -79,7 +79,8 @@ config USB_MUSB_TUSB6010
 
 config USB_MUSB_OMAP2PLUS
        tristate "OMAP2430 and onwards"
-       depends on ARCH_OMAP2PLUS && USB && OMAP_CONTROL_PHY
+       depends on ARCH_OMAP2PLUS && USB
+       depends on OMAP_CONTROL_PHY || !OMAP_CONTROL_PHY
        select GENERIC_PHY
 
 config USB_MUSB_AM35X
index 403fab7..7b3035f 100644 (file)
@@ -126,6 +126,9 @@ struct phy_control *am335x_get_phy_control(struct device *dev)
                return NULL;
 
        dev = bus_find_device(&platform_bus_type, NULL, node, match);
+       if (!dev)
+               return NULL;
+
        ctrl_usb = dev_get_drvdata(dev);
        if (!ctrl_usb)
                return NULL;
index 3086dec..8eb68a3 100644 (file)
@@ -604,6 +604,7 @@ static const struct usb_device_id id_table_combined[] = {
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) },
        /*
         * ELV devices:
         */
@@ -1883,8 +1884,12 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
 {
        struct usb_device *udev = serial->dev;
 
-       if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) ||
-           (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2")))
+       if (udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems"))
+               return ftdi_jtag_probe(serial);
+
+       if (udev->product &&
+               (!strcmp(udev->product, "BeagleBone/XDS100V2") ||
+                !strcmp(udev->product, "SNAP Connect E10")))
                return ftdi_jtag_probe(serial);
 
        return 0;
index 56b1b55..4e4f46f 100644 (file)
  */
 #define FTDI_NT_ORIONLXM_PID   0x7c90  /* OrionLXm Substation Automation Platform */
 
+/*
+ * Synapse Wireless product ids (FTDI_VID)
+ * http://www.synapse-wireless.com
+ */
+#define FTDI_SYNAPSE_SS200_PID 0x9090 /* SS200 - SNAP Stick 200 */
+
 
 /********************************/
 /** third-party VID/PID combos **/
index dd97d8b..4f7e072 100644 (file)
@@ -61,6 +61,7 @@ struct keyspan_pda_private {
 /* For Xircom PGSDB9 and older Entrega version of the same device */
 #define XIRCOM_VENDOR_ID               0x085a
 #define XIRCOM_FAKE_ID                 0x8027
+#define XIRCOM_FAKE_ID_2               0x8025 /* "PGMFHUB" serial */
 #define ENTREGA_VENDOR_ID              0x1645
 #define ENTREGA_FAKE_ID                        0x8093
 
@@ -70,6 +71,7 @@ static const struct usb_device_id id_table_combined[] = {
 #endif
 #ifdef XIRCOM
        { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
+       { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
        { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
 #endif
        { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
@@ -93,6 +95,7 @@ static const struct usb_device_id id_table_fake[] = {
 #ifdef XIRCOM
 static const struct usb_device_id id_table_fake_xircom[] = {
        { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
+       { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
        { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
        { }
 };
index 8257042..c85ea53 100644 (file)
@@ -113,6 +113,13 @@ UNUSUAL_DEV(0x0bc2, 0xab2a, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_ATA_1X),
 
+/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
+UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
+               "Initio Corporation",
+               "",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_ATA_1X),
+
 /* Reported-by: Tom Arild Naess <tanaess@gmail.com> */
 UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999,
                "JMicron",
index 8d4f3f1..71df240 100644 (file)
@@ -1956,10 +1956,9 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
                goto out;
        }
        /*
-        * Now register the TCM vhost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
+        * Now register the TCM vhost virtual I_T Nexus as active.
         */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
 
index 42b87f9..8b6f6d5 100644 (file)
@@ -164,20 +164,15 @@ static void __init omapdss_walk_device(struct device_node *node, bool root)
 
                pn = of_graph_get_remote_port_parent(n);
 
-               if (!pn) {
-                       of_node_put(n);
+               if (!pn)
                        continue;
-               }
 
                if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
                        of_node_put(pn);
-                       of_node_put(n);
                        continue;
                }
 
                omapdss_walk_device(pn, false);
-
-               of_node_put(n);
        }
 }
 
index 0413157..6a356e3 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/balloon_compaction.h>
 #include <linux/oom.h>
+#include <linux/wait.h>
 
 /*
  * Balloon device works in 4K page units.  So each page is pointed to by
@@ -334,17 +335,25 @@ static int virtballoon_oom_notify(struct notifier_block *self,
 static int balloon(void *_vballoon)
 {
        struct virtio_balloon *vb = _vballoon;
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
 
        set_freezable();
        while (!kthread_should_stop()) {
                s64 diff;
 
                try_to_freeze();
-               wait_event_interruptible(vb->config_change,
-                                        (diff = towards_target(vb)) != 0
-                                        || vb->need_stats_update
-                                        || kthread_should_stop()
-                                        || freezing(current));
+
+               add_wait_queue(&vb->config_change, &wait);
+               for (;;) {
+                       if ((diff = towards_target(vb)) != 0 ||
+                           vb->need_stats_update ||
+                           kthread_should_stop() ||
+                           freezing(current))
+                               break;
+                       wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
+               }
+               remove_wait_queue(&vb->config_change, &wait);
+
                if (vb->need_stats_update)
                        stats_handle_request(vb);
                if (diff > 0)
@@ -499,6 +508,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
        if (err < 0)
                goto out_oom_notify;
 
+       virtio_device_ready(vdev);
+
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
                err = PTR_ERR(vb->thread);
index cad5698..6010d7e 100644 (file)
@@ -156,22 +156,95 @@ static void vm_get(struct virtio_device *vdev, unsigned offset,
                   void *buf, unsigned len)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
-       u8 *ptr = buf;
-       int i;
+       void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
+       u8 b;
+       __le16 w;
+       __le32 l;
 
-       for (i = 0; i < len; i++)
-               ptr[i] = readb(vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
+       if (vm_dev->version == 1) {
+               u8 *ptr = buf;
+               int i;
+
+               for (i = 0; i < len; i++)
+                       ptr[i] = readb(base + offset + i);
+               return;
+       }
+
+       switch (len) {
+       case 1:
+               b = readb(base + offset);
+               memcpy(buf, &b, sizeof b);
+               break;
+       case 2:
+               w = cpu_to_le16(readw(base + offset));
+               memcpy(buf, &w, sizeof w);
+               break;
+       case 4:
+               l = cpu_to_le32(readl(base + offset));
+               memcpy(buf, &l, sizeof l);
+               break;
+       case 8:
+               l = cpu_to_le32(readl(base + offset));
+               memcpy(buf, &l, sizeof l);
+               l = cpu_to_le32(ioread32(base + offset + sizeof l));
+               memcpy(buf + sizeof l, &l, sizeof l);
+               break;
+       default:
+               BUG();
+       }
 }
 
 static void vm_set(struct virtio_device *vdev, unsigned offset,
                   const void *buf, unsigned len)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
-       const u8 *ptr = buf;
-       int i;
+       void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
+       u8 b;
+       __le16 w;
+       __le32 l;
 
-       for (i = 0; i < len; i++)
-               writeb(ptr[i], vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
+       if (vm_dev->version == 1) {
+               const u8 *ptr = buf;
+               int i;
+
+               for (i = 0; i < len; i++)
+                       writeb(ptr[i], base + offset + i);
+
+               return;
+       }
+
+       switch (len) {
+       case 1:
+               memcpy(&b, buf, sizeof b);
+               writeb(b, base + offset);
+               break;
+       case 2:
+               memcpy(&w, buf, sizeof w);
+               writew(le16_to_cpu(w), base + offset);
+               break;
+       case 4:
+               memcpy(&l, buf, sizeof l);
+               writel(le32_to_cpu(l), base + offset);
+               break;
+       case 8:
+               memcpy(&l, buf, sizeof l);
+               writel(le32_to_cpu(l), base + offset);
+               memcpy(&l, buf + sizeof l, sizeof l);
+               writel(le32_to_cpu(l), base + offset + sizeof l);
+               break;
+       default:
+               BUG();
+       }
+}
+
+static u32 vm_generation(struct virtio_device *vdev)
+{
+       struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+
+       if (vm_dev->version == 1)
+               return 0;
+       else
+               return readl(vm_dev->base + VIRTIO_MMIO_CONFIG_GENERATION);
 }
 
 static u8 vm_get_status(struct virtio_device *vdev)
@@ -440,6 +513,7 @@ static const char *vm_bus_name(struct virtio_device *vdev)
 static const struct virtio_config_ops virtio_mmio_config_ops = {
        .get            = vm_get,
        .set            = vm_set,
+       .generation     = vm_generation,
        .get_status     = vm_get_status,
        .set_status     = vm_set_status,
        .reset          = vm_reset,
index c8def68..0deaa4f 100644 (file)
 #define PDC_WDT_MIN_TIMEOUT            1
 #define PDC_WDT_DEF_TIMEOUT            64
 
-static int heartbeat;
+static int heartbeat = PDC_WDT_DEF_TIMEOUT;
 module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
-       "(default = " __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds "
+       "(default=" __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
@@ -191,6 +191,7 @@ static int pdc_wdt_probe(struct platform_device *pdev)
        pdc_wdt->wdt_dev.ops = &pdc_wdt_ops;
        pdc_wdt->wdt_dev.max_timeout = 1 << PDC_WDT_CONFIG_DELAY_MASK;
        pdc_wdt->wdt_dev.parent = &pdev->dev;
+       watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
 
        ret = watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev);
        if (ret < 0) {
@@ -232,7 +233,6 @@ static int pdc_wdt_probe(struct platform_device *pdev)
        watchdog_set_nowayout(&pdc_wdt->wdt_dev, nowayout);
 
        platform_set_drvdata(pdev, pdc_wdt);
-       watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
 
        ret = watchdog_register_device(&pdc_wdt->wdt_dev);
        if (ret)
index a87f6df..938b987 100644 (file)
@@ -133,7 +133,7 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
        u32 reg;
        struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
        void __iomem *wdt_base = mtk_wdt->wdt_base;
-       u32 ret;
+       int ret;
 
        ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
        if (ret < 0)
index b812462..94d9680 100644 (file)
@@ -55,6 +55,23 @@ config XEN_BALLOON_MEMORY_HOTPLUG
 
          In that case step 3 should be omitted.
 
+config XEN_BALLOON_MEMORY_HOTPLUG_LIMIT
+       int "Hotplugged memory limit (in GiB) for a PV guest"
+       default 512 if X86_64
+       default 4 if X86_32
+       range 0 64 if X86_32
+       depends on XEN_HAVE_PVMMU
+       depends on XEN_BALLOON_MEMORY_HOTPLUG
+       help
+         Maxmium amount of memory (in GiB) that a PV guest can be
+         expanded to when using memory hotplug.
+
+         A PV guest can have more memory than this limit if is
+         started with a larger maximum.
+
+         This value is used to allocate enough space in internal
+         tables needed for physical memory administration.
+
 config XEN_SCRUB_PAGES
        bool "Scrub pages before returning them to system"
        depends on XEN_BALLOON
index 0b52d92..fd93369 100644 (file)
@@ -229,6 +229,29 @@ static enum bp_state reserve_additional_memory(long credit)
        balloon_hotplug = round_up(balloon_hotplug, PAGES_PER_SECTION);
        nid = memory_add_physaddr_to_nid(hotplug_start_paddr);
 
+#ifdef CONFIG_XEN_HAVE_PVMMU
+        /*
+         * add_memory() will build page tables for the new memory so
+         * the p2m must contain invalid entries so the correct
+         * non-present PTEs will be written.
+         *
+         * If a failure occurs, the original (identity) p2m entries
+         * are not restored since this region is now known not to
+         * conflict with any devices.
+         */ 
+       if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+               unsigned long pfn, i;
+
+               pfn = PFN_DOWN(hotplug_start_paddr);
+               for (i = 0; i < balloon_hotplug; i++) {
+                       if (!set_phys_to_machine(pfn + i, INVALID_P2M_ENTRY)) {
+                               pr_warn("set_phys_to_machine() failed, no memory added\n");
+                               return BP_ECANCELED;
+                       }
+                }
+       }
+#endif
+
        rc = add_memory(nid, hotplug_start_paddr, balloon_hotplug << PAGE_SHIFT);
 
        if (rc) {
index 9faca6a..42bd55a 100644 (file)
@@ -1659,11 +1659,8 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg,
                         name);
                goto out;
        }
-       /*
-        * Now register the TCM pvscsi virtual I_T Nexus as active with the
-        * call to __transport_register_session()
-        */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       /* Now register the TCM pvscsi virtual I_T Nexus as active. */
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
 
index d2468bf..a91795e 100644 (file)
@@ -699,8 +699,10 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
        boff = tmp % bsize;
        if (boff) {
                bh = affs_bread_ino(inode, bidx, 0);
-               if (IS_ERR(bh))
-                       return PTR_ERR(bh);
+               if (IS_ERR(bh)) {
+                       written = PTR_ERR(bh);
+                       goto err_first_bh;
+               }
                tmp = min(bsize - boff, to - from);
                BUG_ON(boff + tmp > bsize || tmp > bsize);
                memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
@@ -712,14 +714,16 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
                bidx++;
        } else if (bidx) {
                bh = affs_bread_ino(inode, bidx - 1, 0);
-               if (IS_ERR(bh))
-                       return PTR_ERR(bh);
+               if (IS_ERR(bh)) {
+                       written = PTR_ERR(bh);
+                       goto err_first_bh;
+               }
        }
        while (from + bsize <= to) {
                prev_bh = bh;
                bh = affs_getemptyblk_ino(inode, bidx);
                if (IS_ERR(bh))
-                       goto out;
+                       goto err_bh;
                memcpy(AFFS_DATA(bh), data + from, bsize);
                if (buffer_new(bh)) {
                        AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
@@ -751,7 +755,7 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
                prev_bh = bh;
                bh = affs_bread_ino(inode, bidx, 1);
                if (IS_ERR(bh))
-                       goto out;
+                       goto err_bh;
                tmp = min(bsize, to - from);
                BUG_ON(tmp > bsize);
                memcpy(AFFS_DATA(bh), data + from, tmp);
@@ -790,12 +794,13 @@ done:
        if (tmp > inode->i_size)
                inode->i_size = AFFS_I(inode)->mmu_private = tmp;
 
+err_first_bh:
        unlock_page(page);
        page_cache_release(page);
 
        return written;
 
-out:
+err_bh:
        bh = prev_bh;
        if (!written)
                written = PTR_ERR(bh);
index 84c3b00..f9c89ca 100644 (file)
@@ -3387,6 +3387,8 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                    struct btrfs_root *root);
+int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root);
 int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr);
 int btrfs_free_block_groups(struct btrfs_fs_info *info);
 int btrfs_read_block_groups(struct btrfs_root *root);
@@ -3909,6 +3911,9 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
                                    loff_t actual_len, u64 *alloc_hint);
 int btrfs_inode_check_errors(struct inode *inode);
 extern const struct dentry_operations btrfs_dentry_operations;
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+void btrfs_test_inode_set_ops(struct inode *inode);
+#endif
 
 /* ioctl.c */
 long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
index f79f385..639f266 100644 (file)
@@ -3921,7 +3921,7 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
        }
        if (btrfs_super_sys_array_size(sb) < sizeof(struct btrfs_disk_key)
                        + sizeof(struct btrfs_chunk)) {
-               printk(KERN_ERR "BTRFS: system chunk array too small %u < %lu\n",
+               printk(KERN_ERR "BTRFS: system chunk array too small %u < %zu\n",
                                btrfs_super_sys_array_size(sb),
                                sizeof(struct btrfs_disk_key)
                                + sizeof(struct btrfs_chunk));
index 6f08045..8b353ad 100644 (file)
@@ -3325,6 +3325,32 @@ out:
        return ret;
 }
 
+int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root)
+{
+       struct btrfs_block_group_cache *cache, *tmp;
+       struct btrfs_transaction *cur_trans = trans->transaction;
+       struct btrfs_path *path;
+
+       if (list_empty(&cur_trans->dirty_bgs) ||
+           !btrfs_test_opt(root, SPACE_CACHE))
+               return 0;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       /* Could add new block groups, use _safe just in case */
+       list_for_each_entry_safe(cache, tmp, &cur_trans->dirty_bgs,
+                                dirty_list) {
+               if (cache->disk_cache_state == BTRFS_DC_CLEAR)
+                       cache_save_setup(cache, trans, path);
+       }
+
+       btrfs_free_path(path);
+       return 0;
+}
+
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root)
 {
@@ -5110,7 +5136,11 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        num_bytes = ALIGN(num_bytes, root->sectorsize);
 
        spin_lock(&BTRFS_I(inode)->lock);
-       BTRFS_I(inode)->outstanding_extents++;
+       nr_extents = (unsigned)div64_u64(num_bytes +
+                                        BTRFS_MAX_EXTENT_SIZE - 1,
+                                        BTRFS_MAX_EXTENT_SIZE);
+       BTRFS_I(inode)->outstanding_extents += nr_extents;
+       nr_extents = 0;
 
        if (BTRFS_I(inode)->outstanding_extents >
            BTRFS_I(inode)->reserved_extents)
@@ -5255,6 +5285,9 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
        if (dropped > 0)
                to_free += btrfs_calc_trans_metadata_size(root, dropped);
 
+       if (btrfs_test_is_dummy_root(root))
+               return;
+
        trace_btrfs_space_reservation(root->fs_info, "delalloc",
                                      btrfs_ino(inode), to_free, 0);
        if (root->fs_info->quota_enabled) {
index c7233ff..d688cfe 100644 (file)
@@ -4968,6 +4968,12 @@ static int release_extent_buffer(struct extent_buffer *eb)
 
                /* Should be safe to release our pages at this point */
                btrfs_release_extent_buffer_page(eb);
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+               if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags))) {
+                       __free_extent_buffer(eb);
+                       return 1;
+               }
+#endif
                call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu);
                return 1;
        }
index da828cf..d2e732d 100644 (file)
@@ -108,6 +108,13 @@ static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
 
 static int btrfs_dirty_inode(struct inode *inode);
 
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+void btrfs_test_inode_set_ops(struct inode *inode)
+{
+       BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
+}
+#endif
+
 static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
                                     struct inode *inode,  struct inode *dir,
                                     const struct qstr *qstr)
@@ -1542,30 +1549,17 @@ static void btrfs_split_extent_hook(struct inode *inode,
                u64 new_size;
 
                /*
-                * We need the largest size of the remaining extent to see if we
-                * need to add a new outstanding extent.  Think of the following
-                * case
-                *
-                * [MEAX_EXTENT_SIZEx2 - 4k][4k]
-                *
-                * The new_size would just be 4k and we'd think we had enough
-                * outstanding extents for this if we only took one side of the
-                * split, same goes for the other direction.  We need to see if
-                * the larger size still is the same amount of extents as the
-                * original size, because if it is we need to add a new
-                * outstanding extent.  But if we split up and the larger size
-                * is less than the original then we are good to go since we've
-                * already accounted for the extra extent in our original
-                * accounting.
+                * See the explanation in btrfs_merge_extent_hook, the same
+                * applies here, just in reverse.
                 */
                new_size = orig->end - split + 1;
-               if ((split - orig->start) > new_size)
-                       new_size = split - orig->start;
-
-               num_extents = div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1,
+               num_extents = div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
                                        BTRFS_MAX_EXTENT_SIZE);
-               if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
-                             BTRFS_MAX_EXTENT_SIZE) < num_extents)
+               new_size = split - orig->start;
+               num_extents += div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
+                                       BTRFS_MAX_EXTENT_SIZE);
+               if (div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1,
+                             BTRFS_MAX_EXTENT_SIZE) >= num_extents)
                        return;
        }
 
@@ -1591,8 +1585,10 @@ static void btrfs_merge_extent_hook(struct inode *inode,
        if (!(other->state & EXTENT_DELALLOC))
                return;
 
-       old_size = other->end - other->start + 1;
-       new_size = old_size + (new->end - new->start + 1);
+       if (new->start > other->start)
+               new_size = new->end - other->start + 1;
+       else
+               new_size = other->end - new->start + 1;
 
        /* we're not bigger than the max, unreserve the space and go */
        if (new_size <= BTRFS_MAX_EXTENT_SIZE) {
@@ -1603,13 +1599,32 @@ static void btrfs_merge_extent_hook(struct inode *inode,
        }
 
        /*
-        * If we grew by another max_extent, just return, we want to keep that
-        * reserved amount.
+        * We have to add up either side to figure out how many extents were
+        * accounted for before we merged into one big extent.  If the number of
+        * extents we accounted for is <= the amount we need for the new range
+        * then we can return, otherwise drop.  Think of it like this
+        *
+        * [ 4k][MAX_SIZE]
+        *
+        * So we've grown the extent by a MAX_SIZE extent, this would mean we
+        * need 2 outstanding extents, on one side we have 1 and the other side
+        * we have 1 so they are == and we can return.  But in this case
+        *
+        * [MAX_SIZE+4k][MAX_SIZE+4k]
+        *
+        * Each range on their own accounts for 2 extents, but merged together
+        * they are only 3 extents worth of accounting, so we need to drop in
+        * this case.
         */
+       old_size = other->end - other->start + 1;
        num_extents = div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1,
                                BTRFS_MAX_EXTENT_SIZE);
+       old_size = new->end - new->start + 1;
+       num_extents += div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1,
+                                BTRFS_MAX_EXTENT_SIZE);
+
        if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
-                     BTRFS_MAX_EXTENT_SIZE) > num_extents)
+                     BTRFS_MAX_EXTENT_SIZE) >= num_extents)
                return;
 
        spin_lock(&BTRFS_I(inode)->lock);
@@ -1686,6 +1701,10 @@ static void btrfs_set_bit_hook(struct inode *inode,
                        spin_unlock(&BTRFS_I(inode)->lock);
                }
 
+               /* For sanity tests */
+               if (btrfs_test_is_dummy_root(root))
+                       return;
+
                __percpu_counter_add(&root->fs_info->delalloc_bytes, len,
                                     root->fs_info->delalloc_batch);
                spin_lock(&BTRFS_I(inode)->lock);
@@ -1741,6 +1760,10 @@ static void btrfs_clear_bit_hook(struct inode *inode,
                    root != root->fs_info->tree_root)
                        btrfs_delalloc_release_metadata(inode, len);
 
+               /* For sanity tests. */
+               if (btrfs_test_is_dummy_root(root))
+                       return;
+
                if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
                    && do_list && !(state->state & EXTENT_NORESERVE))
                        btrfs_free_reserved_data_space(inode, len);
@@ -7213,7 +7236,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
        u64 start = iblock << inode->i_blkbits;
        u64 lockstart, lockend;
        u64 len = bh_result->b_size;
-       u64 orig_len = len;
+       u64 *outstanding_extents = NULL;
        int unlock_bits = EXTENT_LOCKED;
        int ret = 0;
 
@@ -7225,6 +7248,16 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
        lockstart = start;
        lockend = start + len - 1;
 
+       if (current->journal_info) {
+               /*
+                * Need to pull our outstanding extents and set journal_info to NULL so
+                * that anything that needs to check if there's a transction doesn't get
+                * confused.
+                */
+               outstanding_extents = current->journal_info;
+               current->journal_info = NULL;
+       }
+
        /*
         * If this errors out it's because we couldn't invalidate pagecache for
         * this range and we need to fallback to buffered.
@@ -7348,11 +7381,20 @@ unlock:
                if (start + len > i_size_read(inode))
                        i_size_write(inode, start + len);
 
-               if (len < orig_len) {
+               /*
+                * If we have an outstanding_extents count still set then we're
+                * within our reservation, otherwise we need to adjust our inode
+                * counter appropriately.
+                */
+               if (*outstanding_extents) {
+                       (*outstanding_extents)--;
+               } else {
                        spin_lock(&BTRFS_I(inode)->lock);
                        BTRFS_I(inode)->outstanding_extents++;
                        spin_unlock(&BTRFS_I(inode)->lock);
                }
+
+               current->journal_info = outstanding_extents;
                btrfs_free_reserved_data_space(inode, len);
        }
 
@@ -7376,6 +7418,8 @@ unlock:
 unlock_err:
        clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                         unlock_bits, 1, 0, &cached_state, GFP_NOFS);
+       if (outstanding_extents)
+               current->journal_info = outstanding_extents;
        return ret;
 }
 
@@ -8075,6 +8119,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
+       u64 outstanding_extents = 0;
        size_t count = 0;
        int flags = 0;
        bool wakeup = true;
@@ -8112,6 +8157,16 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                ret = btrfs_delalloc_reserve_space(inode, count);
                if (ret)
                        goto out;
+               outstanding_extents = div64_u64(count +
+                                               BTRFS_MAX_EXTENT_SIZE - 1,
+                                               BTRFS_MAX_EXTENT_SIZE);
+
+               /*
+                * We need to know how many extents we reserved so that we can
+                * do the accounting properly if we go over the number we
+                * originally calculated.  Abuse current->journal_info for this.
+                */
+               current->journal_info = &outstanding_extents;
        } else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK,
                                     &BTRFS_I(inode)->runtime_flags)) {
                inode_dio_done(inode);
@@ -8124,6 +8179,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                        iter, offset, btrfs_get_blocks_direct, NULL,
                        btrfs_submit_direct, flags);
        if (rw & WRITE) {
+               current->journal_info = NULL;
                if (ret < 0 && ret != -EIOCBQUEUED)
                        btrfs_delalloc_release_space(inode, count);
                else if (ret >= 0 && (size_t)ret < count)
index 97159a8..058c79e 100644 (file)
@@ -1259,7 +1259,7 @@ static int comp_oper(struct btrfs_qgroup_operation *oper1,
        if (oper1->seq < oper2->seq)
                return -1;
        if (oper1->seq > oper2->seq)
-               return -1;
+               return 1;
        if (oper1->ref_root < oper2->ref_root)
                return -1;
        if (oper1->ref_root > oper2->ref_root)
index a116b55..054fc0d 100644 (file)
@@ -911,6 +911,197 @@ out:
        return ret;
 }
 
+static int test_extent_accounting(void)
+{
+       struct inode *inode = NULL;
+       struct btrfs_root *root = NULL;
+       int ret = -ENOMEM;
+
+       inode = btrfs_new_test_inode();
+       if (!inode) {
+               test_msg("Couldn't allocate inode\n");
+               return ret;
+       }
+
+       root = btrfs_alloc_dummy_root();
+       if (IS_ERR(root)) {
+               test_msg("Couldn't allocate root\n");
+               goto out;
+       }
+
+       root->fs_info = btrfs_alloc_dummy_fs_info();
+       if (!root->fs_info) {
+               test_msg("Couldn't allocate dummy fs info\n");
+               goto out;
+       }
+
+       BTRFS_I(inode)->root = root;
+       btrfs_test_inode_set_ops(inode);
+
+       /* [BTRFS_MAX_EXTENT_SIZE] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, 0, BTRFS_MAX_EXTENT_SIZE - 1,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 1) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 1, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE][4k] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE,
+                                       BTRFS_MAX_EXTENT_SIZE + 4095, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE/2][4K HOLE][the rest] */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree,
+                              BTRFS_MAX_EXTENT_SIZE >> 1,
+                              (BTRFS_MAX_EXTENT_SIZE >> 1) + 4095,
+                              EXTENT_DELALLOC | EXTENT_DIRTY |
+                              EXTENT_UPTODATE | EXTENT_DO_ACCOUNTING, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE][4K] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE >> 1,
+                                       (BTRFS_MAX_EXTENT_SIZE >> 1) + 4095,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /*
+        * [BTRFS_MAX_EXTENT_SIZE+4K][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4K]
+        *
+        * I'm artificially adding 2 to outstanding_extents because in the
+        * buffered IO case we'd add things up as we go, but I don't feel like
+        * doing that here, this isn't the interesting case we want to test.
+        */
+       BTRFS_I(inode)->outstanding_extents += 2;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE + 8192,
+                                       (BTRFS_MAX_EXTENT_SIZE << 1) + 12287,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 4) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 4, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE+4k][4k][BTRFS_MAX_EXTENT_SIZE+4k] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE+4096,
+                                       BTRFS_MAX_EXTENT_SIZE+8191, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 3) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 3, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE+4k][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4k] */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree,
+                              BTRFS_MAX_EXTENT_SIZE+4096,
+                              BTRFS_MAX_EXTENT_SIZE+8191,
+                              EXTENT_DIRTY | EXTENT_DELALLOC |
+                              EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 4) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 4, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /*
+        * Refill the hole again just for good measure, because I thought it
+        * might fail and I'd rather satisfy my paranoia at this point.
+        */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE+4096,
+                                       BTRFS_MAX_EXTENT_SIZE+8191, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 3) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 3, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* Empty */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
+                              EXTENT_DIRTY | EXTENT_DELALLOC |
+                              EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 0, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+       ret = 0;
+out:
+       if (ret)
+               clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
+                                EXTENT_DIRTY | EXTENT_DELALLOC |
+                                EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                                NULL, GFP_NOFS);
+       iput(inode);
+       btrfs_free_dummy_root(root);
+       return ret;
+}
+
 int btrfs_test_inodes(void)
 {
        int ret;
@@ -924,5 +1115,9 @@ int btrfs_test_inodes(void)
        if (ret)
                return ret;
        test_msg("Running hole first btrfs_get_extent test\n");
-       return test_hole_first();
+       ret = test_hole_first();
+       if (ret)
+               return ret;
+       test_msg("Running outstanding_extents tests\n");
+       return test_extent_accounting();
 }
index 88e51ad..8be4278 100644 (file)
@@ -1023,17 +1023,13 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
        u64 old_root_bytenr;
        u64 old_root_used;
        struct btrfs_root *tree_root = root->fs_info->tree_root;
-       bool extent_root = (root->objectid == BTRFS_EXTENT_TREE_OBJECTID);
 
        old_root_used = btrfs_root_used(&root->root_item);
-       btrfs_write_dirty_block_groups(trans, root);
 
        while (1) {
                old_root_bytenr = btrfs_root_bytenr(&root->root_item);
                if (old_root_bytenr == root->node->start &&
-                   old_root_used == btrfs_root_used(&root->root_item) &&
-                   (!extent_root ||
-                    list_empty(&trans->transaction->dirty_bgs)))
+                   old_root_used == btrfs_root_used(&root->root_item))
                        break;
 
                btrfs_set_root_node(&root->root_item, root->node);
@@ -1044,14 +1040,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
                        return ret;
 
                old_root_used = btrfs_root_used(&root->root_item);
-               if (extent_root) {
-                       ret = btrfs_write_dirty_block_groups(trans, root);
-                       if (ret)
-                               return ret;
-               }
-               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-               if (ret)
-                       return ret;
        }
 
        return 0;
@@ -1068,6 +1056,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                                         struct btrfs_root *root)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
+       struct list_head *dirty_bgs = &trans->transaction->dirty_bgs;
        struct list_head *next;
        struct extent_buffer *eb;
        int ret;
@@ -1095,11 +1084,15 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
        if (ret)
                return ret;
 
+       ret = btrfs_setup_space_cache(trans, root);
+       if (ret)
+               return ret;
+
        /* run_qgroups might have added some more refs */
        ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
        if (ret)
                return ret;
-
+again:
        while (!list_empty(&fs_info->dirty_cowonly_roots)) {
                next = fs_info->dirty_cowonly_roots.next;
                list_del_init(next);
@@ -1112,8 +1105,23 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                ret = update_cowonly_root(trans, root);
                if (ret)
                        return ret;
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               if (ret)
+                       return ret;
        }
 
+       while (!list_empty(dirty_bgs)) {
+               ret = btrfs_write_dirty_block_groups(trans, root);
+               if (ret)
+                       return ret;
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               if (ret)
+                       return ret;
+       }
+
+       if (!list_empty(&fs_info->dirty_cowonly_roots))
+               goto again;
+
        list_add_tail(&fs_info->extent_root->dirty_list,
                      &trans->transaction->switch_commits);
        btrfs_after_dev_replace_commit(fs_info);
@@ -1811,6 +1819,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
                wait_for_commit(root, cur_trans);
 
+               if (unlikely(cur_trans->aborted))
+                       ret = cur_trans->aborted;
+
                btrfs_put_transaction(cur_trans);
 
                return ret;
index 4ac7445..aa0dc25 100644 (file)
@@ -1,6 +1,9 @@
 /*
  *   fs/cifs/cifsencrypt.c
  *
+ *   Encryption and hashing operations relating to NTLM, NTLMv2.  See MS-NLMP
+ *   for more detailed information
+ *
  *   Copyright (C) International Business Machines  Corp., 2005,2013
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
@@ -515,7 +518,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
                                 __func__);
                        return rc;
                }
-       } else if (ses->serverName) {
+       } else {
+               /* We use ses->serverName if no domain name available */
                len = strlen(ses->serverName);
 
                server = kmalloc(2 + (len * 2), GFP_KERNEL);
index d3aa999..480cf9c 100644 (file)
@@ -1599,6 +1599,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                pr_warn("CIFS: username too long\n");
                                goto cifs_parse_mount_err;
                        }
+
+                       kfree(vol->username);
                        vol->username = kstrdup(string, GFP_KERNEL);
                        if (!vol->username)
                                goto cifs_parse_mount_err;
@@ -1700,6 +1702,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                goto cifs_parse_mount_err;
                        }
 
+                       kfree(vol->domainname);
                        vol->domainname = kstrdup(string, GFP_KERNEL);
                        if (!vol->domainname) {
                                pr_warn("CIFS: no memory for domainname\n");
@@ -1731,6 +1734,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        }
 
                         if (strncasecmp(string, "default", 7) != 0) {
+                               kfree(vol->iocharset);
                                vol->iocharset = kstrdup(string,
                                                         GFP_KERNEL);
                                if (!vol->iocharset) {
@@ -2913,8 +2917,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
                 * calling name ends in null (byte 16) from old smb
                 * convention.
                 */
-               if (server->workstation_RFC1001_name &&
-                   server->workstation_RFC1001_name[0] != 0)
+               if (server->workstation_RFC1001_name[0] != 0)
                        rfc1002mangle(ses_init_buf->trailer.
                                      session_req.calling_name,
                                      server->workstation_RFC1001_name,
@@ -3692,6 +3695,12 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
 #endif /* CIFS_WEAK_PW_HASH */
                rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
                                        bcc_ptr, nls_codepage);
+               if (rc) {
+                       cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n",
+                                __func__, rc);
+                       cifs_buf_release(smb_buffer);
+                       return rc;
+               }
 
                bcc_ptr += CIFS_AUTH_RESP_SIZE;
                if (ses->capabilities & CAP_UNICODE) {
index a94b3e6..ca30c39 100644 (file)
@@ -1823,6 +1823,7 @@ refind_writable:
                        cifsFileInfo_put(inv_file);
                        spin_lock(&cifs_file_list_lock);
                        ++refind;
+                       inv_file = NULL;
                        goto refind_writable;
                }
        }
index 2d4f372..3e126d7 100644 (file)
@@ -771,6 +771,8 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
                                cifs_buf_release(srchinf->ntwrk_buf_start);
                        }
                        kfree(srchinf);
+                       if (rc)
+                               goto cgii_exit;
        } else
                goto cgii_exit;
 
index 689f035..22dfdf1 100644 (file)
@@ -322,7 +322,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 
        /* return pointer to beginning of data area, ie offset from SMB start */
        if ((*off != 0) && (*len != 0))
-               return hdr->ProtocolId + *off;
+               return (char *)(&hdr->ProtocolId[0]) + *off;
        else
                return NULL;
 }
index 96b5d40..eab05e1 100644 (file)
@@ -684,7 +684,8 @@ smb2_clone_range(const unsigned int xid,
 
                        /* No need to change MaxChunks since already set to 1 */
                        chunk_sizes_updated = true;
-               }
+               } else
+                       goto cchunk_out;
        }
 
 cchunk_out:
index 3417340..65cd7a8 100644 (file)
@@ -1218,7 +1218,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        struct smb2_ioctl_req *req;
        struct smb2_ioctl_rsp *rsp;
        struct TCP_Server_Info *server;
-       struct cifs_ses *ses = tcon->ses;
+       struct cifs_ses *ses;
        struct kvec iov[2];
        int resp_buftype;
        int num_iovecs;
@@ -1233,6 +1233,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        if (plen)
                *plen = 0;
 
+       if (tcon)
+               ses = tcon->ses;
+       else
+               return -EIO;
+
        if (ses && (ses->server))
                server = ses->server;
        else
@@ -1296,14 +1301,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base;
 
        if ((rc != 0) && (rc != -EINVAL)) {
-               if (tcon)
-                       cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+               cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
                goto ioctl_exit;
        } else if (rc == -EINVAL) {
                if ((opcode != FSCTL_SRV_COPYCHUNK_WRITE) &&
                    (opcode != FSCTL_SRV_COPYCHUNK)) {
-                       if (tcon)
-                               cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+                       cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
                        goto ioctl_exit;
                }
        }
@@ -1629,7 +1632,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 
        rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
 
-       if ((rc != 0) && tcon)
+       if (rc != 0)
                cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
 
        free_rsp_buf(resp_buftype, iov[0].iov_base);
@@ -2114,7 +2117,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        struct kvec iov[2];
        int rc = 0;
        int len;
-       int resp_buftype;
+       int resp_buftype = CIFS_NO_BUFFER;
        unsigned char *bufptr;
        struct TCP_Server_Info *server;
        struct cifs_ses *ses = tcon->ses;
index e907052..32a8bbd 100644 (file)
@@ -53,6 +53,18 @@ struct wb_writeback_work {
        struct completion *done;        /* set if the caller waits */
 };
 
+/*
+ * If an inode is constantly having its pages dirtied, but then the
+ * updates stop dirtytime_expire_interval seconds in the past, it's
+ * possible for the worst case time between when an inode has its
+ * timestamps updated and when they finally get written out to be two
+ * dirtytime_expire_intervals.  We set the default to 12 hours (in
+ * seconds), which means most of the time inodes will have their
+ * timestamps written to disk after 12 hours, but in the worst case a
+ * few inodes might not their timestamps updated for 24 hours.
+ */
+unsigned int dirtytime_expire_interval = 12 * 60 * 60;
+
 /**
  * writeback_in_progress - determine whether there is writeback in progress
  * @bdi: the device's backing_dev_info structure.
@@ -275,8 +287,8 @@ static int move_expired_inodes(struct list_head *delaying_queue,
 
        if ((flags & EXPIRE_DIRTY_ATIME) == 0)
                older_than_this = work->older_than_this;
-       else if ((work->reason == WB_REASON_SYNC) == 0) {
-               expire_time = jiffies - (HZ * 86400);
+       else if (!work->for_sync) {
+               expire_time = jiffies - (dirtytime_expire_interval * HZ);
                older_than_this = &expire_time;
        }
        while (!list_empty(delaying_queue)) {
@@ -458,6 +470,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
                 */
                redirty_tail(inode, wb);
        } else if (inode->i_state & I_DIRTY_TIME) {
+               inode->dirtied_when = jiffies;
                list_move(&inode->i_wb_list, &wb->b_dirty_time);
        } else {
                /* The inode is clean. Remove from writeback lists. */
@@ -505,12 +518,17 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
        spin_lock(&inode->i_lock);
 
        dirty = inode->i_state & I_DIRTY;
-       if (((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) &&
-            (inode->i_state & I_DIRTY_TIME)) ||
-           (inode->i_state & I_DIRTY_TIME_EXPIRED)) {
-               dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED;
-               trace_writeback_lazytime(inode);
-       }
+       if (inode->i_state & I_DIRTY_TIME) {
+               if ((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) ||
+                   unlikely(inode->i_state & I_DIRTY_TIME_EXPIRED) ||
+                   unlikely(time_after(jiffies,
+                                       (inode->dirtied_time_when +
+                                        dirtytime_expire_interval * HZ)))) {
+                       dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED;
+                       trace_writeback_lazytime(inode);
+               }
+       } else
+               inode->i_state &= ~I_DIRTY_TIME_EXPIRED;
        inode->i_state &= ~dirty;
 
        /*
@@ -1131,6 +1149,56 @@ void wakeup_flusher_threads(long nr_pages, enum wb_reason reason)
        rcu_read_unlock();
 }
 
+/*
+ * Wake up bdi's periodically to make sure dirtytime inodes gets
+ * written back periodically.  We deliberately do *not* check the
+ * b_dirtytime list in wb_has_dirty_io(), since this would cause the
+ * kernel to be constantly waking up once there are any dirtytime
+ * inodes on the system.  So instead we define a separate delayed work
+ * function which gets called much more rarely.  (By default, only
+ * once every 12 hours.)
+ *
+ * If there is any other write activity going on in the file system,
+ * this function won't be necessary.  But if the only thing that has
+ * happened on the file system is a dirtytime inode caused by an atime
+ * update, we need this infrastructure below to make sure that inode
+ * eventually gets pushed out to disk.
+ */
+static void wakeup_dirtytime_writeback(struct work_struct *w);
+static DECLARE_DELAYED_WORK(dirtytime_work, wakeup_dirtytime_writeback);
+
+static void wakeup_dirtytime_writeback(struct work_struct *w)
+{
+       struct backing_dev_info *bdi;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
+               if (list_empty(&bdi->wb.b_dirty_time))
+                       continue;
+               bdi_wakeup_thread(bdi);
+       }
+       rcu_read_unlock();
+       schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
+}
+
+static int __init start_dirtytime_writeback(void)
+{
+       schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
+       return 0;
+}
+__initcall(start_dirtytime_writeback);
+
+int dirtytime_interval_handler(struct ctl_table *table, int write,
+                              void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int ret;
+
+       ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+       if (ret == 0 && write)
+               mod_delayed_work(system_wq, &dirtytime_work, 0);
+       return ret;
+}
+
 static noinline void block_dump___mark_inode_dirty(struct inode *inode)
 {
        if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) {
@@ -1269,8 +1337,13 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                        }
 
                        inode->dirtied_when = jiffies;
-                       list_move(&inode->i_wb_list, dirtytime ?
-                                 &bdi->wb.b_dirty_time : &bdi->wb.b_dirty);
+                       if (dirtytime)
+                               inode->dirtied_time_when = jiffies;
+                       if (inode->i_state & (I_DIRTY_INODE | I_DIRTY_PAGES))
+                               list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
+                       else
+                               list_move(&inode->i_wb_list,
+                                         &bdi->wb.b_dirty_time);
                        spin_unlock(&bdi->wb.list_lock);
                        trace_writeback_dirty_inode_enqueue(inode);
 
index ed19a7d..39706c5 100644 (file)
@@ -890,8 +890,8 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
 
        newpage = buf->page;
 
-       if (WARN_ON(!PageUptodate(newpage)))
-               return -EIO;
+       if (!PageUptodate(newpage))
+               SetPageUptodate(newpage);
 
        ClearPageMappedToDisk(newpage);
 
@@ -1353,6 +1353,17 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
        return err;
 }
 
+static int fuse_dev_open(struct inode *inode, struct file *file)
+{
+       /*
+        * The fuse device's file's private_data is used to hold
+        * the fuse_conn(ection) when it is mounted, and is used to
+        * keep track of whether the file has been mounted already.
+        */
+       file->private_data = NULL;
+       return 0;
+}
+
 static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
                              unsigned long nr_segs, loff_t pos)
 {
@@ -1797,6 +1808,9 @@ copy_finish:
 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
                       unsigned int size, struct fuse_copy_state *cs)
 {
+       /* Don't try to move pages (yet) */
+       cs->move_pages = 0;
+
        switch (code) {
        case FUSE_NOTIFY_POLL:
                return fuse_notify_poll(fc, size, cs);
@@ -2217,6 +2231,7 @@ static int fuse_dev_fasync(int fd, struct file *file, int on)
 
 const struct file_operations fuse_dev_operations = {
        .owner          = THIS_MODULE,
+       .open           = fuse_dev_open,
        .llseek         = no_llseek,
        .read           = do_sync_read,
        .aio_read       = fuse_dev_read,
index 6e560d5..754fdf8 100644 (file)
@@ -131,13 +131,16 @@ skip:
        hfs_bnode_write(node, entry, data_off + key_len, entry_len);
        hfs_bnode_dump(node);
 
-       if (new_node) {
-               /* update parent key if we inserted a key
-                * at the start of the first node
-                */
-               if (!rec && new_node != node)
-                       hfs_brec_update_parent(fd);
+       /*
+        * update parent key if we inserted a key
+        * at the start of the node and it is not the new node
+        */
+       if (!rec && new_node != node) {
+               hfs_bnode_read_key(node, fd->search_key, data_off + size);
+               hfs_brec_update_parent(fd);
+       }
 
+       if (new_node) {
                hfs_bnode_put(fd->bnode);
                if (!new_node->parent) {
                        hfs_btree_inc_height(tree);
@@ -168,9 +171,6 @@ skip:
                goto again;
        }
 
-       if (!rec)
-               hfs_brec_update_parent(fd);
-
        return 0;
 }
 
@@ -370,6 +370,8 @@ again:
        if (IS_ERR(parent))
                return PTR_ERR(parent);
        __hfs_brec_find(parent, fd, hfs_find_rec_by_key);
+       if (fd->record < 0)
+               return -ENOENT;
        hfs_bnode_dump(parent);
        rec = fd->record;
 
index b684e8a..2bacb99 100644 (file)
@@ -207,6 +207,7 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
                goto out_free;
        }
 
+       of->event = atomic_read(&of->kn->attr.open->event);
        ops = kernfs_ops(of->kn);
        if (ops->read)
                len = ops->read(of, buf, len, *ppos);
index 528fedf..40bc384 100644 (file)
@@ -1388,9 +1388,8 @@ any_leases_conflict(struct inode *inode, struct file_lock *breaker)
 int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
 {
        int error = 0;
-       struct file_lock *new_fl;
        struct file_lock_context *ctx = inode->i_flctx;
-       struct file_lock *fl;
+       struct file_lock *new_fl, *fl, *tmp;
        unsigned long break_time;
        int want_write = (mode & O_ACCMODE) != O_RDONLY;
        LIST_HEAD(dispose);
@@ -1420,7 +1419,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
                        break_time++;   /* so that 0 means no break time */
        }
 
-       list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
+       list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) {
                if (!leases_conflict(fl, new_fl))
                        continue;
                if (want_write) {
index cdbc78c..03d647b 100644 (file)
@@ -137,7 +137,7 @@ nfsd4_block_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
        seg->offset = iomap.offset;
        seg->length = iomap.length;
 
-       dprintk("GET: %lld:%lld %d\n", bex->foff, bex->len, bex->es);
+       dprintk("GET: 0x%llx:0x%llx %d\n", bex->foff, bex->len, bex->es);
        return 0;
 
 out_error:
index 9da89fd..9aa2796 100644 (file)
@@ -122,19 +122,19 @@ nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
 
                p = xdr_decode_hyper(p, &bex.foff);
                if (bex.foff & (block_size - 1)) {
-                       dprintk("%s: unaligned offset %lld\n",
+                       dprintk("%s: unaligned offset 0x%llx\n",
                                __func__, bex.foff);
                        goto fail;
                }
                p = xdr_decode_hyper(p, &bex.len);
                if (bex.len & (block_size - 1)) {
-                       dprintk("%s: unaligned length %lld\n",
+                       dprintk("%s: unaligned length 0x%llx\n",
                                __func__, bex.foff);
                        goto fail;
                }
                p = xdr_decode_hyper(p, &bex.soff);
                if (bex.soff & (block_size - 1)) {
-                       dprintk("%s: unaligned disk offset %lld\n",
+                       dprintk("%s: unaligned disk offset 0x%llx\n",
                                __func__, bex.soff);
                        goto fail;
                }
index 3c1bfa1..6904213 100644 (file)
@@ -118,7 +118,7 @@ void nfsd4_setup_layout_type(struct svc_export *exp)
 {
        struct super_block *sb = exp->ex_path.mnt->mnt_sb;
 
-       if (exp->ex_flags & NFSEXP_NOPNFS)
+       if (!(exp->ex_flags & NFSEXP_PNFS))
                return;
 
        if (sb->s_export_op->get_uuid &&
@@ -440,15 +440,14 @@ nfsd4_return_file_layout(struct nfs4_layout *lp, struct nfsd4_layout_seg *seg,
                        list_move_tail(&lp->lo_perstate, reaplist);
                        return;
                }
-               end = seg->offset;
+               lo->offset = layout_end(seg);
        } else {
                /* retain the whole layout segment on a split. */
                if (layout_end(seg) < end) {
                        dprintk("%s: split not supported\n", __func__);
                        return;
                }
-
-               lo->offset = layout_end(seg);
+               end = seg->offset;
        }
 
        layout_update_len(lo, end);
@@ -513,6 +512,9 @@ nfsd4_return_client_layouts(struct svc_rqst *rqstp,
 
        spin_lock(&clp->cl_lock);
        list_for_each_entry_safe(ls, n, &clp->cl_lo_states, ls_perclnt) {
+               if (ls->ls_layout_type != lrp->lr_layout_type)
+                       continue;
+
                if (lrp->lr_return_type == RETURN_FSID &&
                    !fh_fsid_match(&ls->ls_stid.sc_file->fi_fhandle,
                                   &cstate->current_fh.fh_handle))
@@ -587,7 +589,7 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
 
        rpc_ntop((struct sockaddr *)&clp->cl_addr, addr_str, sizeof(addr_str));
 
-       nfsd4_cb_layout_fail(ls);
+       trace_layout_recall_fail(&ls->ls_stid.sc_stateid);
 
        printk(KERN_WARNING
                "nfsd: client %s failed to respond to layout recall. "
index d30bea8..92b9d97 100644 (file)
@@ -1237,8 +1237,8 @@ nfsd4_getdeviceinfo(struct svc_rqst *rqstp,
                nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb, gdp);
 
        gdp->gd_notify_types &= ops->notify_types;
-       exp_put(exp);
 out:
+       exp_put(exp);
        return nfserr;
 }
 
index d2f2c37..8ba1d88 100644 (file)
@@ -3221,7 +3221,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
        } else
                nfs4_free_openowner(&oo->oo_owner);
        spin_unlock(&clp->cl_lock);
-       return oo;
+       return ret;
 }
 
 static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
@@ -5062,7 +5062,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
        } else
                nfs4_free_lockowner(&lo->lo_owner);
        spin_unlock(&clp->cl_lock);
-       return lo;
+       return ret;
 }
 
 static void
index df5e66c..5fb7e78 100644 (file)
@@ -1562,7 +1562,11 @@ nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp,
        p = xdr_decode_hyper(p, &lgp->lg_seg.offset);
        p = xdr_decode_hyper(p, &lgp->lg_seg.length);
        p = xdr_decode_hyper(p, &lgp->lg_minlength);
-       nfsd4_decode_stateid(argp, &lgp->lg_sid);
+
+       status = nfsd4_decode_stateid(argp, &lgp->lg_sid);
+       if (status)
+               return status;
+
        READ_BUF(4);
        lgp->lg_maxcount = be32_to_cpup(p++);
 
@@ -1580,7 +1584,11 @@ nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp,
        p = xdr_decode_hyper(p, &lcp->lc_seg.offset);
        p = xdr_decode_hyper(p, &lcp->lc_seg.length);
        lcp->lc_reclaim = be32_to_cpup(p++);
-       nfsd4_decode_stateid(argp, &lcp->lc_sid);
+
+       status = nfsd4_decode_stateid(argp, &lcp->lc_sid);
+       if (status)
+               return status;
+
        READ_BUF(4);
        lcp->lc_newoffset = be32_to_cpup(p++);
        if (lcp->lc_newoffset) {
@@ -1628,7 +1636,11 @@ nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp,
                READ_BUF(16);
                p = xdr_decode_hyper(p, &lrp->lr_seg.offset);
                p = xdr_decode_hyper(p, &lrp->lr_seg.length);
-               nfsd4_decode_stateid(argp, &lrp->lr_sid);
+
+               status = nfsd4_decode_stateid(argp, &lrp->lr_sid);
+               if (status)
+                       return status;
+
                READ_BUF(4);
                lrp->lrf_body_len = be32_to_cpup(p++);
                if (lrp->lrf_body_len > 0) {
@@ -4123,7 +4135,7 @@ nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
                return nfserr_resource;
        *p++ = cpu_to_be32(lrp->lrs_present);
        if (lrp->lrs_present)
-               nfsd4_encode_stateid(xdr, &lrp->lr_sid);
+               return nfsd4_encode_stateid(xdr, &lrp->lr_sid);
        return nfs_ok;
 }
 #endif /* CONFIG_NFSD_PNFS */
index 83a9694..46ec934 100644 (file)
@@ -165,13 +165,17 @@ int nfsd_reply_cache_init(void)
 {
        unsigned int hashsize;
        unsigned int i;
+       int status = 0;
 
        max_drc_entries = nfsd_cache_size_limit();
        atomic_set(&num_drc_entries, 0);
        hashsize = nfsd_hashsize(max_drc_entries);
        maskbits = ilog2(hashsize);
 
-       register_shrinker(&nfsd_reply_cache_shrinker);
+       status = register_shrinker(&nfsd_reply_cache_shrinker);
+       if (status)
+               return status;
+
        drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep),
                                        0, 0, NULL);
        if (!drc_slab)
index b90952f..5f0d199 100644 (file)
@@ -529,8 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data)
 {
        struct ovl_fs *ufs = sb->s_fs_info;
 
-       if (!(*flags & MS_RDONLY) &&
-           (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY)))
+       if (!(*flags & MS_RDONLY) && !ufs->upper_mnt)
                return -EROFS;
 
        return 0;
@@ -615,9 +614,19 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
                        break;
 
                default:
+                       pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p);
                        return -EINVAL;
                }
        }
+
+       /* Workdir is useless in non-upper mount */
+       if (!config->upperdir && config->workdir) {
+               pr_info("overlayfs: option \"workdir=%s\" is useless in a non-upper mount, ignore\n",
+                       config->workdir);
+               kfree(config->workdir);
+               config->workdir = NULL;
+       }
+
        return 0;
 }
 
@@ -837,7 +846,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_stack_depth = 0;
        if (ufs->config.upperdir) {
-               /* FIXME: workdir is not needed for a R/O mount */
                if (!ufs->config.workdir) {
                        pr_err("overlayfs: missing 'workdir'\n");
                        goto out_free_config;
@@ -847,6 +855,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                if (err)
                        goto out_free_config;
 
+               /* Upper fs should not be r/o */
+               if (upperpath.mnt->mnt_sb->s_flags & MS_RDONLY) {
+                       pr_err("overlayfs: upper fs is r/o, try multi-lower layers mount\n");
+                       err = -EINVAL;
+                       goto out_put_upperpath;
+               }
+
                err = ovl_mount_dir(ufs->config.workdir, &workpath);
                if (err)
                        goto out_put_upperpath;
@@ -869,8 +884,14 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        err = -EINVAL;
        stacklen = ovl_split_lowerdirs(lowertmp);
-       if (stacklen > OVL_MAX_STACK)
+       if (stacklen > OVL_MAX_STACK) {
+               pr_err("overlayfs: too many lower directries, limit is %d\n",
+                      OVL_MAX_STACK);
                goto out_free_lowertmp;
+       } else if (!ufs->config.upperdir && stacklen == 1) {
+               pr_err("overlayfs: at least 2 lowerdir are needed while upperdir nonexistent\n");
+               goto out_free_lowertmp;
+       }
 
        stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL);
        if (!stack)
@@ -932,8 +953,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                ufs->numlower++;
        }
 
-       /* If the upper fs is r/o or nonexistent, we mark overlayfs r/o too */
-       if (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY))
+       /* If the upper fs is nonexistent, we mark overlayfs r/o too */
+       if (!ufs->upper_mnt)
                sb->s_flags |= MS_RDONLY;
 
        sb->s_d_op = &ovl_dentry_operations;
index 956b75d..6dee68d 100644 (file)
@@ -1325,6 +1325,9 @@ out:
 
 static int pagemap_open(struct inode *inode, struct file *file)
 {
+       /* do not disclose physical addresses: attack vector */
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
        pr_warn_once("Bits 55-60 of /proc/PID/pagemap entries are about "
                        "to stop being page-shift some time soon. See the "
                        "linux/Documentation/vm/pagemap.txt for details.\n");
index 63c0b01..62c4077 100644 (file)
@@ -253,7 +253,6 @@ struct drm_ioctl_desc {
        unsigned int cmd;
        int flags;
        drm_ioctl_t *func;
-       unsigned int cmd_drv;
        const char *name;
 };
 
@@ -262,8 +261,13 @@ struct drm_ioctl_desc {
  * ioctl, for use by drm_ioctl().
  */
 
-#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags)                        \
-       [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl, .name = #ioctl}
+#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags)                                \
+       [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {        \
+               .cmd = DRM_IOCTL_##ioctl,                               \
+               .func = _func,                                          \
+               .flags = _flags,                                        \
+               .name = #ioctl                                          \
+        }
 
 /* Event queued up for userspace to read */
 struct drm_pending_event {
index 829280b..d665781 100644 (file)
@@ -87,20 +87,34 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
 
 /* default implementations for state handling */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
+void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
+                                             struct drm_crtc_state *state);
 struct drm_crtc_state *
 drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
+void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+                                           struct drm_crtc_state *state);
 void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
                                          struct drm_crtc_state *state);
 
 void drm_atomic_helper_plane_reset(struct drm_plane *plane);
+void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
+                                              struct drm_plane_state *state);
 struct drm_plane_state *
 drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
+void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+                                            struct drm_plane_state *state);
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
                                          struct drm_plane_state *state);
 
 void drm_atomic_helper_connector_reset(struct drm_connector *connector);
+void
+__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
+                                          struct drm_connector_state *state);
 struct drm_connector_state *
 drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
+void
+__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+                                           struct drm_connector_state *state);
 void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
                                          struct drm_connector_state *state);
 
index 7b5c661..2e80ad1 100644 (file)
@@ -53,7 +53,6 @@ struct fence;
 #define DRM_MODE_OBJECT_FB 0xfbfbfbfb
 #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
 #define DRM_MODE_OBJECT_PLANE 0xeeeeeeee
-#define DRM_MODE_OBJECT_BRIDGE 0xbdbdbdbd
 #define DRM_MODE_OBJECT_ANY 0
 
 struct drm_mode_object {
index 1fbcc96..13ff44b 100644 (file)
@@ -29,6 +29,7 @@
 struct drm_connector;
 struct drm_device;
 struct drm_panel;
+struct display_timing;
 
 /**
  * struct drm_panel_funcs - perform operations on a given panel
@@ -38,6 +39,8 @@ struct drm_panel;
  * @enable: enable panel (turn on back light, etc.)
  * @get_modes: add modes to the connector that the panel is attached to and
  * return the number of modes added
+ * @get_timings: copy display timings into the provided array and return
+ * the number of display timings available
  *
  * The .prepare() function is typically called before the display controller
  * starts to transmit video data. Panel drivers can use this to turn the panel
@@ -68,6 +71,8 @@ struct drm_panel_funcs {
        int (*prepare)(struct drm_panel *panel);
        int (*enable)(struct drm_panel *panel);
        int (*get_modes)(struct drm_panel *panel);
+       int (*get_timings)(struct drm_panel *panel, unsigned int num_timings,
+                          struct display_timing *timings);
 };
 
 struct drm_panel {
index 7c55dd5..66203b2 100644 (file)
@@ -114,6 +114,7 @@ struct vgic_ops {
        void    (*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr);
        u64     (*get_elrsr)(const struct kvm_vcpu *vcpu);
        u64     (*get_eisr)(const struct kvm_vcpu *vcpu);
+       void    (*clear_eisr)(struct kvm_vcpu *vcpu);
        u32     (*get_interrupt_status)(const struct kvm_vcpu *vcpu);
        void    (*enable_underflow)(struct kvm_vcpu *vcpu);
        void    (*disable_underflow)(struct kvm_vcpu *vcpu);
index 2646aed..fd23978 100644 (file)
@@ -375,6 +375,7 @@ int dm_create(int minor, struct mapped_device **md);
  */
 struct mapped_device *dm_get_md(dev_t dev);
 void dm_get(struct mapped_device *md);
+int dm_hold(struct mapped_device *md);
 void dm_put(struct mapped_device *md);
 
 /*
index b4d71b5..f4131e8 100644 (file)
@@ -604,6 +604,7 @@ struct inode {
        struct mutex            i_mutex;
 
        unsigned long           dirtied_when;   /* jiffies of first dirtying */
+       unsigned long           dirtied_time_when;
 
        struct hlist_node       i_hash;
        struct list_head        i_wb_list;      /* backing dev IO list */
index 464f338..d2ba7d3 100644 (file)
@@ -135,6 +135,7 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id);
 u32 host1x_syncpt_id(struct host1x_syncpt *sp);
 u32 host1x_syncpt_read_min(struct host1x_syncpt *sp);
 u32 host1x_syncpt_read_max(struct host1x_syncpt *sp);
+u32 host1x_syncpt_read(struct host1x_syncpt *sp);
 int host1x_syncpt_incr(struct host1x_syncpt *sp);
 u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
 int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
index 781974a..ffbc034 100644 (file)
 #define GICR_PROPBASER_WaWb            (5U << 7)
 #define GICR_PROPBASER_RaWaWt          (6U << 7)
 #define GICR_PROPBASER_RaWaWb          (7U << 7)
+#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7)
 #define GICR_PROPBASER_IDBITS_MASK     (0x1f)
 
+#define GICR_PENDBASER_NonShareable    (0U << 10)
+#define GICR_PENDBASER_InnerShareable  (1U << 10)
+#define GICR_PENDBASER_OuterShareable  (2U << 10)
+#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10)
+#define GICR_PENDBASER_nCnB            (0U << 7)
+#define GICR_PENDBASER_nC              (1U << 7)
+#define GICR_PENDBASER_RaWt            (2U << 7)
+#define GICR_PENDBASER_RaWb            (3U << 7)
+#define GICR_PENDBASER_WaWt            (4U << 7)
+#define GICR_PENDBASER_WaWb            (5U << 7)
+#define GICR_PENDBASER_RaWaWt          (6U << 7)
+#define GICR_PENDBASER_RaWaWb          (7U << 7)
+#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7)
+
 /*
  * Re-Distributor registers, offsets from SGI_base
  */
 #define GITS_CBASER_WaWb               (5UL << 59)
 #define GITS_CBASER_RaWaWt             (6UL << 59)
 #define GITS_CBASER_RaWaWb             (7UL << 59)
+#define GITS_CBASER_CACHEABILITY_MASK  (7UL << 59)
 #define GITS_CBASER_NonShareable       (0UL << 10)
 #define GITS_CBASER_InnerShareable     (1UL << 10)
 #define GITS_CBASER_OuterShareable     (2UL << 10)
 #define GITS_BASER_WaWb                        (5UL << 59)
 #define GITS_BASER_RaWaWt              (6UL << 59)
 #define GITS_BASER_RaWaWb              (7UL << 59)
+#define GITS_BASER_CACHEABILITY_MASK   (7UL << 59)
 #define GITS_BASER_TYPE_SHIFT          (56)
 #define GITS_BASER_TYPE(r)             (((r) >> GITS_BASER_TYPE_SHIFT) & 7)
 #define GITS_BASER_ENTRY_SIZE_SHIFT    (48)
index 7bf01d7..1ce79a7 100644 (file)
@@ -4,5 +4,6 @@
 #include <linux/compiler.h>
 
 unsigned long lcm(unsigned long a, unsigned long b) __attribute_const__;
+unsigned long lcm_not_zero(unsigned long a, unsigned long b) __attribute_const__;
 
 #endif /* _LCM_H */
index fc03efa..6b08cc1 100644 (file)
@@ -232,6 +232,7 @@ enum {
                                              * led */
        ATA_FLAG_NO_DIPM        = (1 << 23), /* host not happy with DIPM */
        ATA_FLAG_LOWTAG         = (1 << 24), /* host wants lowest available tag */
+       ATA_FLAG_SAS_HOST       = (1 << 25), /* SAS host */
 
        /* bits 24:31 of ap->flags are reserved for LLD specific flags */
 
index fb0390a..ee7b1ce 100644 (file)
@@ -2999,6 +2999,9 @@ enum usb_irq_events {
 #define PALMAS_GPADC_TRIM15                                    0x0E
 #define PALMAS_GPADC_TRIM16                                    0x0F
 
+/* TPS659038 regen2_ctrl offset iss different from palmas */
+#define TPS659038_REGEN2_CTRL                                  0x12
+
 /* TPS65917 Interrupt registers */
 
 /* Registers for function INTERRUPT */
index 42999fe..b03485b 100644 (file)
@@ -344,6 +344,10 @@ struct module {
        unsigned long *ftrace_callsites;
 #endif
 
+#ifdef CONFIG_LIVEPATCH
+       bool klp_alive;
+#endif
+
 #ifdef CONFIG_MODULE_UNLOAD
        /* What modules depend on me? */
        struct list_head source_list;
index 429d179..2787388 100644 (file)
@@ -965,9 +965,12 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  *     Used to add FDB entries to dump requests. Implementers should add
  *     entries to skb and update idx with the number of entries.
  *
- * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh)
+ * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh,
+ *                          u16 flags)
  * int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq,
  *                          struct net_device *dev, u32 filter_mask)
+ * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
+ *                          u16 flags);
  *
  * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
  *     Called to change device carrier. Soft-devices (like dummy, team, etc)
@@ -2182,6 +2185,12 @@ void netdev_freemem(struct net_device *dev);
 void synchronize_net(void);
 int init_dummy_netdev(struct net_device *dev);
 
+DECLARE_PER_CPU(int, xmit_recursion);
+static inline int dev_recursion_level(void)
+{
+       return this_cpu_read(xmit_recursion);
+}
+
 struct net_device *dev_get_by_index(struct net *net, int ifindex);
 struct net_device *__dev_get_by_index(struct net *net, int ifindex);
 struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
index befef42..7bc92e0 100644 (file)
@@ -14,6 +14,8 @@
 #ifndef __LINUX_OF_GRAPH_H
 #define __LINUX_OF_GRAPH_H
 
+#include <linux/types.h>
+
 /**
  * struct of_endpoint - the OF graph endpoint data structure
  * @port: identifier (value of reg property) of a port this endpoint belongs to
@@ -26,9 +28,21 @@ struct of_endpoint {
        const struct device_node *local_node;
 };
 
+/**
+ * for_each_endpoint_of_node - iterate over every endpoint in a device node
+ * @parent: parent device node containing ports and endpoints
+ * @child: loop variable pointing to the current endpoint node
+ *
+ * When breaking out of the loop, of_node_put(child) has to be called manually.
+ */
+#define for_each_endpoint_of_node(parent, child) \
+       for (child = of_graph_get_next_endpoint(parent, NULL); child != NULL; \
+            child = of_graph_get_next_endpoint(parent, child))
+
 #ifdef CONFIG_OF
 int of_graph_parse_endpoint(const struct device_node *node,
                                struct of_endpoint *endpoint);
+struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id);
 struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
                                        struct device_node *previous);
 struct device_node *of_graph_get_remote_port_parent(
@@ -42,6 +56,12 @@ static inline int of_graph_parse_endpoint(const struct device_node *node,
        return -ENOSYS;
 }
 
+static inline struct device_node *of_graph_get_port_by_id(
+                                       struct device_node *node, u32 id)
+{
+       return NULL;
+}
+
 static inline struct device_node *of_graph_get_next_endpoint(
                                        const struct device_node *parent,
                                        struct device_node *previous)
index 72c0415..18eccef 100644 (file)
@@ -82,7 +82,7 @@ static inline int pinctrl_gpio_direction_output(unsigned gpio)
 
 static inline struct pinctrl * __must_check pinctrl_get(struct device *dev)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline void pinctrl_put(struct pinctrl *p)
@@ -93,7 +93,7 @@ static inline struct pinctrl_state * __must_check pinctrl_lookup_state(
                                                        struct pinctrl *p,
                                                        const char *name)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline int pinctrl_select_state(struct pinctrl *p,
@@ -104,7 +104,7 @@ static inline int pinctrl_select_state(struct pinctrl *p,
 
 static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline void devm_pinctrl_put(struct pinctrl *p)
index d4ad5b5..045f709 100644 (file)
@@ -316,7 +316,7 @@ struct regulator_desc {
  * @driver_data: private regulator data
  * @of_node: OpenFirmware node to parse for device tree bindings (may be
  *           NULL).
- * @regmap: regmap to use for core regmap helpers if dev_get_regulator() is
+ * @regmap: regmap to use for core regmap helpers if dev_get_regmap() is
  *          insufficient.
  * @ena_gpio_initialized: GPIO controlling regulator enable was properly
  *                        initialized, meaning that >= 0 is a valid gpio
index 6d77432..a419b65 100644 (file)
@@ -1625,11 +1625,11 @@ struct task_struct {
 
        /*
         * numa_faults_locality tracks if faults recorded during the last
-        * scan window were remote/local. The task scan period is adapted
-        * based on the locality of the faults with different weights
-        * depending on whether they were shared or private faults
+        * scan window were remote/local or failed to migrate. The task scan
+        * period is adapted based on the locality of the faults with different
+        * weights depending on whether they were shared or private faults
         */
-       unsigned long numa_faults_locality[2];
+       unsigned long numa_faults_locality[3];
 
        unsigned long numa_pages_migrated;
 #endif /* CONFIG_NUMA_BALANCING */
@@ -1719,6 +1719,7 @@ struct task_struct {
 #define TNF_NO_GROUP   0x02
 #define TNF_SHARED     0x04
 #define TNF_FAULT_LOCAL        0x08
+#define TNF_MIGRATE_FAIL 0x10
 
 #ifdef CONFIG_NUMA_BALANCING
 extern void task_numa_fault(int last_node, int node, int pages, int flags);
index 30007af..f54d665 100644 (file)
@@ -948,6 +948,13 @@ static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
        to->l4_hash = from->l4_hash;
 };
 
+static inline void skb_sender_cpu_clear(struct sk_buff *skb)
+{
+#ifdef CONFIG_XPS
+       skb->sender_cpu = 0;
+#endif
+}
+
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
 {
index c57d8ea..59a7889 100644 (file)
@@ -60,17 +60,17 @@ struct rpc_xprt;
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
 void           rpc_register_sysctl(void);
 void           rpc_unregister_sysctl(void);
-int            sunrpc_debugfs_init(void);
+void           sunrpc_debugfs_init(void);
 void           sunrpc_debugfs_exit(void);
-int            rpc_clnt_debugfs_register(struct rpc_clnt *);
+void           rpc_clnt_debugfs_register(struct rpc_clnt *);
 void           rpc_clnt_debugfs_unregister(struct rpc_clnt *);
-int            rpc_xprt_debugfs_register(struct rpc_xprt *);
+void           rpc_xprt_debugfs_register(struct rpc_xprt *);
 void           rpc_xprt_debugfs_unregister(struct rpc_xprt *);
 #else
-static inline int
+static inline void
 sunrpc_debugfs_init(void)
 {
-       return 0;
+       return;
 }
 
 static inline void
@@ -79,10 +79,10 @@ sunrpc_debugfs_exit(void)
        return;
 }
 
-static inline int
+static inline void
 rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
 {
-       return 0;
+       return;
 }
 
 static inline void
@@ -91,10 +91,10 @@ rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
        return;
 }
 
-static inline int
+static inline void
 rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
 {
-       return 0;
+       return;
 }
 
 static inline void
index d9a4905..6e0ce8c 100644 (file)
@@ -227,9 +227,23 @@ struct skb_data {  /* skb->cb is one of these */
        struct urb              *urb;
        struct usbnet           *dev;
        enum skb_state          state;
-       size_t                  length;
+       long                    length;
+       unsigned long           packets;
 };
 
+/* Drivers that set FLAG_MULTI_PACKET must call this in their
+ * tx_fixup method before returning an skb.
+ */
+static inline void
+usbnet_set_skb_tx_stats(struct sk_buff *skb,
+                       unsigned long packets, long bytes_delta)
+{
+       struct skb_data *entry = (struct skb_data *) skb->cb;
+
+       entry->packets = packets;
+       entry->length = bytes_delta;
+}
+
 extern int usbnet_open(struct net_device *net);
 extern int usbnet_stop(struct net_device *net);
 extern netdev_tx_t usbnet_start_xmit(struct sk_buff *skb,
index 0004833..b2dd371 100644 (file)
@@ -130,6 +130,7 @@ extern int vm_dirty_ratio;
 extern unsigned long vm_dirty_bytes;
 extern unsigned int dirty_writeback_interval;
 extern unsigned int dirty_expire_interval;
+extern unsigned int dirtytime_expire_interval;
 extern int vm_highmem_is_dirtyable;
 extern int block_dump;
 extern int laptop_mode;
@@ -146,6 +147,8 @@ extern int dirty_ratio_handler(struct ctl_table *table, int write,
 extern int dirty_bytes_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos);
+int dirtytime_interval_handler(struct ctl_table *table, int write,
+                              void __user *buffer, size_t *lenp, loff_t *ppos);
 
 struct ctl_table;
 int dirty_writeback_centisecs_handler(struct ctl_table *, int,
index a8ae4e7..0fb99a2 100644 (file)
@@ -481,6 +481,7 @@ void dst_init(void);
 enum {
        XFRM_LOOKUP_ICMP = 1 << 0,
        XFRM_LOOKUP_QUEUE = 1 << 1,
+       XFRM_LOOKUP_KEEP_DST_REF = 1 << 2,
 };
 
 struct flowi;
index 025c61c..6cc1eaf 100644 (file)
@@ -453,22 +453,6 @@ static __inline__ void inet_reset_saddr(struct sock *sk)
 
 #endif
 
-static inline int sk_mc_loop(struct sock *sk)
-{
-       if (!sk)
-               return 1;
-       switch (sk->sk_family) {
-       case AF_INET:
-               return inet_sk(sk)->mc_loop;
-#if IS_ENABLED(CONFIG_IPV6)
-       case AF_INET6:
-               return inet6_sk(sk)->mc_loop;
-#endif
-       }
-       WARN_ON(1);
-       return 1;
-}
-
 bool ip_call_ra_chain(struct sk_buff *skb);
 
 /*
index 1d09b46..eda131d 100644 (file)
@@ -174,7 +174,8 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
 
 static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
 {
-       struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
+       struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
+                               inet6_sk(skb->sk) : NULL;
 
        return (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) ?
               skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
index 534e1f2..57639fc 100644 (file)
@@ -79,6 +79,16 @@ void nf_log_packet(struct net *net,
                   const struct nf_loginfo *li,
                   const char *fmt, ...);
 
+__printf(8, 9)
+void nf_log_trace(struct net *net,
+                 u_int8_t pf,
+                 unsigned int hooknum,
+                 const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct nf_loginfo *li,
+                 const char *fmt, ...);
+
 struct nf_log_buf;
 
 struct nf_log_buf *nf_log_buf_open(void);
index ab186b1..e4079c2 100644 (file)
@@ -1762,6 +1762,8 @@ struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie);
 
 struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie);
 
+bool sk_mc_loop(struct sock *sk);
+
 static inline bool sk_can_gso(const struct sock *sk)
 {
        return net_gso_ok(sk->sk_route_caps, sk->sk_gso_type);
index eabd3a0..c73e7ab 100644 (file)
@@ -91,6 +91,7 @@ struct vxlanhdr {
 
 #define VXLAN_N_VID     (1u << 24)
 #define VXLAN_VID_MASK  (VXLAN_N_VID - 1)
+#define VXLAN_VNI_MASK  (VXLAN_VID_MASK << 8)
 #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
 
 struct vxlan_metadata {
index db81c65..d61be72 100644 (file)
@@ -111,6 +111,7 @@ void        array_free(void *array, int n);
 void   target_core_setup_sub_cits(struct se_subsystem_api *);
 
 /* attribute helpers from target_core_device.c for backend drivers */
+bool   se_dev_check_wce(struct se_device *);
 int    se_dev_set_max_unmap_lba_count(struct se_device *, u32);
 int    se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
 int    se_dev_set_unmap_granularity(struct se_device *, u32);
index 23d5615..22317d2 100644 (file)
@@ -7,27 +7,26 @@
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
 
-struct device;
-struct regmap;
+#include "../../../drivers/base/regmap/internal.h"
 
 /*
  * Log register events
  */
 DECLARE_EVENT_CLASS(regmap_reg,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val),
+       TP_ARGS(map, reg, val),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   reg             )
-               __field(        unsigned int,   val             )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   reg                     )
+               __field(        unsigned int,   val                     )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->reg = reg;
                __entry->val = val;
        ),
@@ -39,45 +38,45 @@ DECLARE_EVENT_CLASS(regmap_reg,
 
 DEFINE_EVENT(regmap_reg, regmap_reg_write,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DEFINE_EVENT(regmap_reg, regmap_reg_read,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DEFINE_EVENT(regmap_reg, regmap_reg_read_cache,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DECLARE_EVENT_CLASS(regmap_block,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count),
+       TP_ARGS(map, reg, count),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   reg             )
-               __field(        int,            count           )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   reg                     )
+               __field(        int,            count                   )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->reg = reg;
                __entry->count = count;
        ),
@@ -89,48 +88,48 @@ DECLARE_EVENT_CLASS(regmap_block,
 
 DEFINE_EVENT(regmap_block, regmap_hw_read_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_read_done,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_write_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_write_done,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 TRACE_EVENT(regcache_sync,
 
-       TP_PROTO(struct device *dev, const char *type,
+       TP_PROTO(struct regmap *map, const char *type,
                 const char *status),
 
-       TP_ARGS(dev, type, status),
+       TP_ARGS(map, type, status),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __string(       status,         status          )
-               __string(       type,           type            )
-               __field(        int,            type            )
+               __string(       name,           regmap_name(map)        )
+               __string(       status,         status                  )
+               __string(       type,           type                    )
+               __field(        int,            type                    )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __assign_str(status, status);
                __assign_str(type, type);
        ),
@@ -141,17 +140,17 @@ TRACE_EVENT(regcache_sync,
 
 DECLARE_EVENT_CLASS(regmap_bool,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag),
+       TP_ARGS(map, flag),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        int,            flag            )
+               __string(       name,           regmap_name(map)        )
+               __field(        int,            flag                    )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->flag = flag;
        ),
 
@@ -161,32 +160,32 @@ DECLARE_EVENT_CLASS(regmap_bool,
 
 DEFINE_EVENT(regmap_bool, regmap_cache_only,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag)
+       TP_ARGS(map, flag)
 
 );
 
 DEFINE_EVENT(regmap_bool, regmap_cache_bypass,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag)
+       TP_ARGS(map, flag)
 
 );
 
 DECLARE_EVENT_CLASS(regmap_async,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev),
+       TP_ARGS(map),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
+               __string(       name,           regmap_name(map)        )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
        ),
 
        TP_printk("%s", __get_str(name))
@@ -194,50 +193,50 @@ DECLARE_EVENT_CLASS(regmap_async,
 
 DEFINE_EVENT(regmap_block, regmap_async_write_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_io_complete,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_complete_start,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_complete_done,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 TRACE_EVENT(regcache_drop_region,
 
-       TP_PROTO(struct device *dev, unsigned int from,
+       TP_PROTO(struct regmap *map, unsigned int from,
                 unsigned int to),
 
-       TP_ARGS(dev, from, to),
+       TP_ARGS(map, from, to),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   from            )
-               __field(        unsigned int,   to              )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   from                    )
+               __field(        unsigned int,   to                      )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->from = from;
                __entry->to = to;
        ),
index 8d1be90..551b673 100644 (file)
@@ -270,7 +270,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE       DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image)
 #define DRM_IOCTL_I915_OVERLAY_ATTRS   DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
 #define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
-#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
+#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
 #define DRM_IOCTL_I915_GEM_WAIT                DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait)
 #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)
index c15d781..5391780 100644 (file)
@@ -36,7 +36,8 @@ struct drm_tegra_gem_create {
 
 struct drm_tegra_gem_mmap {
        __u32 handle;
-       __u32 offset;
+       __u32 pad;
+       __u64 offset;
 };
 
 struct drm_tegra_syncpt_read {
index b0a8130..2f62ab2 100644 (file)
@@ -973,7 +973,8 @@ struct input_keymap_entry {
  */
 #define MT_TOOL_FINGER         0
 #define MT_TOOL_PEN            1
-#define MT_TOOL_MAX            1
+#define MT_TOOL_PALM           2
+#define MT_TOOL_MAX            2
 
 /*
  * Values describing the status of a force-feedback effect
index 4742f2c..d3bd6ff 100644 (file)
@@ -47,7 +47,7 @@
  * exported filesystem.
  */
 #define        NFSEXP_V4ROOT           0x10000
-#define NFSEXP_NOPNFS          0x20000
+#define NFSEXP_PNFS            0x20000
 
 /* All flags that we claim to support.  (Note we don't support NOACL.) */
 #define NFSEXP_ALLFLAGS                0x3FE7F
index 3c53eec..19c66fc 100644 (file)
@@ -60,7 +60,7 @@ struct virtio_blk_config {
        __u32 size_max;
        /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
        __u32 seg_max;
-       /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */
+       /* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
        struct virtio_blk_geometry {
                __u16 cylinders;
                __u8 heads;
@@ -119,7 +119,11 @@ struct virtio_blk_config {
 #define VIRTIO_BLK_T_BARRIER   0x80000000
 #endif /* !VIRTIO_BLK_NO_LEGACY */
 
-/* This is the first element of the read scatter-gather list. */
+/*
+ * This comes first in the read scatter-gather list.
+ * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
+ * this is the first element of the read scatter-gather list.
+ */
 struct virtio_blk_outhdr {
        /* VIRTIO_BLK_T* */
        __virtio32 type;
index 42b9370..cc18ef8 100644 (file)
 
 #include <linux/virtio_types.h>
 
-#define VIRTIO_SCSI_CDB_SIZE   32
-#define VIRTIO_SCSI_SENSE_SIZE 96
+/* Default values of the CDB and sense data size configuration fields */
+#define VIRTIO_SCSI_CDB_DEFAULT_SIZE   32
+#define VIRTIO_SCSI_SENSE_DEFAULT_SIZE 96
+
+#ifndef VIRTIO_SCSI_CDB_SIZE
+#define VIRTIO_SCSI_CDB_SIZE VIRTIO_SCSI_CDB_DEFAULT_SIZE
+#endif
+#ifndef VIRTIO_SCSI_SENSE_SIZE
+#define VIRTIO_SCSI_SENSE_SIZE VIRTIO_SCSI_SENSE_DEFAULT_SIZE
+#endif
 
 /* SCSI command request, followed by data-out */
 struct virtio_scsi_cmd_req {
index a20e4a3..0530e5a 100644 (file)
 #define VIDISD14C_ALPHA1_B_LIMIT               0xf
 #define VIDISD14C_ALPHA1_B(_x)                 ((_x) << 0)
 
+#define VIDW_ALPHA                             0x021c
+#define VIDW_ALPHA_R(_x)                       ((_x) << 16)
+#define VIDW_ALPHA_G(_x)                       ((_x) << 8)
+#define VIDW_ALPHA_B(_x)                       ((_x) << 0)
+
 /* Video buffer addresses */
 #define VIDW_BUF_START(_buff)                  (0xA0 + ((_buff) * 8))
 #define VIDW_BUF_START1(_buff)                 (0xA4 + ((_buff) * 8))
 #define BLENDCON_NEW_8BIT_ALPHA_VALUE          (1 << 0)
 #define BLENDCON_NEW_4BIT_ALPHA_VALUE          (0 << 0)
 
+/* Display port clock control */
+#define DP_MIE_CLKCON                          0x27c
+#define DP_MIE_CLK_DISABLE                     0x0
+#define DP_MIE_CLK_DP_ENABLE                   0x2
+#define DP_MIE_CLK_MIE_ENABLE                  0x3
+
 /* Notes on per-window bpp settings
  *
  * Value       Win0     Win1     Win2     Win3     Win 4
index f04daab..2fabc06 100644 (file)
@@ -3591,7 +3591,7 @@ static void put_event(struct perf_event *event)
        ctx = perf_event_ctx_lock_nested(event, SINGLE_DEPTH_NESTING);
        WARN_ON_ONCE(ctx->parent_ctx);
        perf_remove_from_context(event, true);
-       mutex_unlock(&ctx->mutex);
+       perf_event_ctx_unlock(event, ctx);
 
        _free_event(event);
 }
@@ -4574,6 +4574,13 @@ static void perf_pending_event(struct irq_work *entry)
 {
        struct perf_event *event = container_of(entry,
                        struct perf_event, pending);
+       int rctx;
+
+       rctx = perf_swevent_get_recursion_context();
+       /*
+        * If we 'fail' here, that's OK, it means recursion is already disabled
+        * and we won't recurse 'further'.
+        */
 
        if (event->pending_disable) {
                event->pending_disable = 0;
@@ -4584,6 +4591,9 @@ static void perf_pending_event(struct irq_work *entry)
                event->pending_wakeup = 0;
                perf_event_wakeup(event);
        }
+
+       if (rctx >= 0)
+               perf_swevent_put_recursion_context(rctx);
 }
 
 /*
index 01ca088..3f9f1d6 100644 (file)
@@ -89,16 +89,28 @@ static bool klp_is_object_loaded(struct klp_object *obj)
 /* sets obj->mod if object is not vmlinux and module is found */
 static void klp_find_object_module(struct klp_object *obj)
 {
+       struct module *mod;
+
        if (!klp_is_module(obj))
                return;
 
        mutex_lock(&module_mutex);
        /*
-        * We don't need to take a reference on the module here because we have
-        * the klp_mutex, which is also taken by the module notifier.  This
-        * prevents any module from unloading until we release the klp_mutex.
+        * We do not want to block removal of patched modules and therefore
+        * we do not take a reference here. The patches are removed by
+        * a going module handler instead.
+        */
+       mod = find_module(obj->name);
+       /*
+        * Do not mess work of the module coming and going notifiers.
+        * Note that the patch might still be needed before the going handler
+        * is called. Module functions can be called even in the GOING state
+        * until mod->exit() finishes. This is especially important for
+        * patches that modify semantic of the functions.
         */
-       obj->mod = find_module(obj->name);
+       if (mod && mod->klp_alive)
+               obj->mod = mod;
+
        mutex_unlock(&module_mutex);
 }
 
@@ -767,6 +779,7 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj)
                return -EINVAL;
 
        obj->state = KLP_DISABLED;
+       obj->mod = NULL;
 
        klp_find_object_module(obj);
 
@@ -961,6 +974,15 @@ static int klp_module_notify(struct notifier_block *nb, unsigned long action,
 
        mutex_lock(&klp_mutex);
 
+       /*
+        * Each module has to know that the notifier has been called.
+        * We never know what module will get patched by a new patch.
+        */
+       if (action == MODULE_STATE_COMING)
+               mod->klp_alive = true;
+       else /* MODULE_STATE_GOING */
+               mod->klp_alive = false;
+
        list_for_each_entry(patch, &klp_patches, list) {
                for (obj = patch->objs; obj->funcs; obj++) {
                        if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
index 88d0d44..ba77ab5 100644 (file)
@@ -633,7 +633,7 @@ static int count_matching_names(struct lock_class *new_class)
        if (!new_class->name)
                return 0;
 
-       list_for_each_entry(class, &all_lock_classes, lock_entry) {
+       list_for_each_entry_rcu(class, &all_lock_classes, lock_entry) {
                if (new_class->key - new_class->subclass == class->key)
                        return class->name_version;
                if (class->name && !strcmp(class->name, new_class->name))
@@ -700,10 +700,12 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
        hash_head = classhashentry(key);
 
        /*
-        * We can walk the hash lockfree, because the hash only
-        * grows, and we are careful when adding entries to the end:
+        * We do an RCU walk of the hash, see lockdep_free_key_range().
         */
-       list_for_each_entry(class, hash_head, hash_entry) {
+       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+               return NULL;
+
+       list_for_each_entry_rcu(class, hash_head, hash_entry) {
                if (class->key == key) {
                        /*
                         * Huh! same key, different name? Did someone trample
@@ -728,7 +730,8 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
        struct lockdep_subclass_key *key;
        struct list_head *hash_head;
        struct lock_class *class;
-       unsigned long flags;
+
+       DEBUG_LOCKS_WARN_ON(!irqs_disabled());
 
        class = look_up_lock_class(lock, subclass);
        if (likely(class))
@@ -750,28 +753,26 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
        key = lock->key->subkeys + subclass;
        hash_head = classhashentry(key);
 
-       raw_local_irq_save(flags);
        if (!graph_lock()) {
-               raw_local_irq_restore(flags);
                return NULL;
        }
        /*
         * We have to do the hash-walk again, to avoid races
         * with another CPU:
         */
-       list_for_each_entry(class, hash_head, hash_entry)
+       list_for_each_entry_rcu(class, hash_head, hash_entry) {
                if (class->key == key)
                        goto out_unlock_set;
+       }
+
        /*
         * Allocate a new key from the static array, and add it to
         * the hash:
         */
        if (nr_lock_classes >= MAX_LOCKDEP_KEYS) {
                if (!debug_locks_off_graph_unlock()) {
-                       raw_local_irq_restore(flags);
                        return NULL;
                }
-               raw_local_irq_restore(flags);
 
                print_lockdep_off("BUG: MAX_LOCKDEP_KEYS too low!");
                dump_stack();
@@ -798,7 +799,6 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
 
        if (verbose(class)) {
                graph_unlock();
-               raw_local_irq_restore(flags);
 
                printk("\nnew class %p: %s", class->key, class->name);
                if (class->name_version > 1)
@@ -806,15 +806,12 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
                printk("\n");
                dump_stack();
 
-               raw_local_irq_save(flags);
                if (!graph_lock()) {
-                       raw_local_irq_restore(flags);
                        return NULL;
                }
        }
 out_unlock_set:
        graph_unlock();
-       raw_local_irq_restore(flags);
 
 out_set_class_cache:
        if (!subclass || force)
@@ -870,11 +867,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
        entry->distance = distance;
        entry->trace = *trace;
        /*
-        * Since we never remove from the dependency list, the list can
-        * be walked lockless by other CPUs, it's only allocation
-        * that must be protected by the spinlock. But this also means
-        * we must make new entries visible only once writes to the
-        * entry become visible - hence the RCU op:
+        * Both allocation and removal are done under the graph lock; but
+        * iteration is under RCU-sched; see look_up_lock_class() and
+        * lockdep_free_key_range().
         */
        list_add_tail_rcu(&entry->entry, head);
 
@@ -1025,7 +1020,9 @@ static int __bfs(struct lock_list *source_entry,
                else
                        head = &lock->class->locks_before;
 
-               list_for_each_entry(entry, head, entry) {
+               DEBUG_LOCKS_WARN_ON(!irqs_disabled());
+
+               list_for_each_entry_rcu(entry, head, entry) {
                        if (!lock_accessed(entry)) {
                                unsigned int cq_depth;
                                mark_lock_accessed(entry, lock);
@@ -2022,7 +2019,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
         * We can walk it lock-free, because entries only get added
         * to the hash:
         */
-       list_for_each_entry(chain, hash_head, entry) {
+       list_for_each_entry_rcu(chain, hash_head, entry) {
                if (chain->chain_key == chain_key) {
 cache_hit:
                        debug_atomic_inc(chain_lookup_hits);
@@ -2996,8 +2993,18 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
        if (unlikely(!debug_locks))
                return;
 
-       if (subclass)
+       if (subclass) {
+               unsigned long flags;
+
+               if (DEBUG_LOCKS_WARN_ON(current->lockdep_recursion))
+                       return;
+
+               raw_local_irq_save(flags);
+               current->lockdep_recursion = 1;
                register_lock_class(lock, subclass, 1);
+               current->lockdep_recursion = 0;
+               raw_local_irq_restore(flags);
+       }
 }
 EXPORT_SYMBOL_GPL(lockdep_init_map);
 
@@ -3887,9 +3894,17 @@ static inline int within(const void *addr, void *start, unsigned long size)
        return addr >= start && addr < start + size;
 }
 
+/*
+ * Used in module.c to remove lock classes from memory that is going to be
+ * freed; and possibly re-used by other modules.
+ *
+ * We will have had one sync_sched() before getting here, so we're guaranteed
+ * nobody will look up these exact classes -- they're properly dead but still
+ * allocated.
+ */
 void lockdep_free_key_range(void *start, unsigned long size)
 {
-       struct lock_class *class, *next;
+       struct lock_class *class;
        struct list_head *head;
        unsigned long flags;
        int i;
@@ -3905,7 +3920,7 @@ void lockdep_free_key_range(void *start, unsigned long size)
                head = classhash_table + i;
                if (list_empty(head))
                        continue;
-               list_for_each_entry_safe(class, next, head, hash_entry) {
+               list_for_each_entry_rcu(class, head, hash_entry) {
                        if (within(class->key, start, size))
                                zap_class(class);
                        else if (within(class->name, start, size))
@@ -3916,11 +3931,25 @@ void lockdep_free_key_range(void *start, unsigned long size)
        if (locked)
                graph_unlock();
        raw_local_irq_restore(flags);
+
+       /*
+        * Wait for any possible iterators from look_up_lock_class() to pass
+        * before continuing to free the memory they refer to.
+        *
+        * sync_sched() is sufficient because the read-side is IRQ disable.
+        */
+       synchronize_sched();
+
+       /*
+        * XXX at this point we could return the resources to the pool;
+        * instead we leak them. We would need to change to bitmap allocators
+        * instead of the linear allocators we have now.
+        */
 }
 
 void lockdep_reset_lock(struct lockdep_map *lock)
 {
-       struct lock_class *class, *next;
+       struct lock_class *class;
        struct list_head *head;
        unsigned long flags;
        int i, j;
@@ -3948,7 +3977,7 @@ void lockdep_reset_lock(struct lockdep_map *lock)
                head = classhash_table + i;
                if (list_empty(head))
                        continue;
-               list_for_each_entry_safe(class, next, head, hash_entry) {
+               list_for_each_entry_rcu(class, head, hash_entry) {
                        int match = 0;
 
                        for (j = 0; j < NR_LOCKDEP_CACHING_CLASSES; j++)
index b3d634e..99fdf94 100644 (file)
@@ -1865,7 +1865,7 @@ static void free_module(struct module *mod)
        kfree(mod->args);
        percpu_modfree(mod);
 
-       /* Free lock-classes: */
+       /* Free lock-classes; relies on the preceding sync_rcu(). */
        lockdep_free_key_range(mod->module_core, mod->core_size);
 
        /* Finally, free the core (containing the module structure) */
@@ -3349,9 +3349,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
        module_bug_cleanup(mod);
        mutex_unlock(&module_mutex);
 
-       /* Free lock-classes: */
-       lockdep_free_key_range(mod->module_core, mod->core_size);
-
        /* we can't deallocate the module until we clear memory protection */
        unset_module_init_ro_nx(mod);
        unset_module_core_ro_nx(mod);
@@ -3375,6 +3372,9 @@ static int load_module(struct load_info *info, const char __user *uargs,
        synchronize_rcu();
        mutex_unlock(&module_mutex);
  free_module:
+       /* Free lock-classes; relies on the preceding sync_rcu() */
+       lockdep_free_key_range(mod->module_core, mod->core_size);
+
        module_deallocate(mod, info);
  free_copy:
        free_copy(info);
index f0f831e..62671f5 100644 (file)
@@ -3034,6 +3034,8 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
        } else {
                if (dl_prio(oldprio))
                        p->dl.dl_boosted = 0;
+               if (rt_prio(oldprio))
+                       p->rt.timeout = 0;
                p->sched_class = &fair_sched_class;
        }
 
index 7ce18f3..bcfe320 100644 (file)
@@ -1609,9 +1609,11 @@ static void update_task_scan_period(struct task_struct *p,
        /*
         * If there were no record hinting faults then either the task is
         * completely idle or all activity is areas that are not of interest
-        * to automatic numa balancing. Scan slower
+        * to automatic numa balancing. Related to that, if there were failed
+        * migration then it implies we are migrating too quickly or the local
+        * node is overloaded. In either case, scan slower
         */
-       if (local + shared == 0) {
+       if (local + shared == 0 || p->numa_faults_locality[2]) {
                p->numa_scan_period = min(p->numa_scan_period_max,
                        p->numa_scan_period << 1);
 
@@ -2080,6 +2082,8 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
 
        if (migrated)
                p->numa_pages_migrated += pages;
+       if (flags & TNF_MIGRATE_FAIL)
+               p->numa_faults_locality[2] += pages;
 
        p->numa_faults[task_faults_idx(NUMA_MEMBUF, mem_node, priv)] += pages;
        p->numa_faults[task_faults_idx(NUMA_CPUBUF, cpu_node, priv)] += pages;
index 88ea2d6..ce410bb 100644 (file)
@@ -1228,6 +1228,14 @@ static struct ctl_table vm_table[] = {
                .extra1         = &zero,
        },
        {
+               .procname       = "dirtytime_expire_seconds",
+               .data           = &dirtytime_expire_interval,
+               .maxlen         = sizeof(dirty_expire_interval),
+               .mode           = 0644,
+               .proc_handler   = dirtytime_interval_handler,
+               .extra1         = &zero,
+       },
+       {
                .procname       = "nr_pdflush_threads",
                .mode           = 0444 /* read-only */,
                .proc_handler   = pdflush_proc_obsolete,
index eb682d5..6aac4be 100644 (file)
@@ -49,6 +49,7 @@ static void bc_set_mode(enum clock_event_mode mode,
  */
 static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
 {
+       int bc_moved;
        /*
         * We try to cancel the timer first. If the callback is on
         * flight on some other cpu then we let it handle it. If we
@@ -60,9 +61,15 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
         * restart the timer because we are in the callback, but we
         * can set the expiry time and let the callback return
         * HRTIMER_RESTART.
+        *
+        * Since we are in the idle loop at this point and because
+        * hrtimer_{start/cancel} functions call into tracing,
+        * calls to these functions must be bound within RCU_NONIDLE.
         */
-       if (hrtimer_try_to_cancel(&bctimer) >= 0) {
-               hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED);
+       RCU_NONIDLE(bc_moved = (hrtimer_try_to_cancel(&bctimer) >= 0) ?
+               !hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED) :
+                       0);
+       if (bc_moved) {
                /* Bind the "device" to the cpu */
                bc->bound_on = smp_processor_id();
        } else if (bc->bound_on == smp_processor_id()) {
index e97dbd5..03d7fcb 100644 (file)
--- a/lib/lcm.c
+++ b/lib/lcm.c
@@ -12,3 +12,14 @@ unsigned long lcm(unsigned long a, unsigned long b)
                return 0;
 }
 EXPORT_SYMBOL_GPL(lcm);
+
+unsigned long lcm_not_zero(unsigned long a, unsigned long b)
+{
+       unsigned long l = lcm(a, b);
+
+       if (l)
+               return l;
+
+       return (b ? : a);
+}
+EXPORT_SYMBOL_GPL(lcm_not_zero);
index 7a85967..f0f5c5c 100644 (file)
@@ -139,6 +139,9 @@ static int lz4_uncompress(const char *source, char *dest, int osize)
                        /* Error: request to write beyond destination buffer */
                        if (cpy > oend)
                                goto _output_error;
+                       if ((ref + COPYLENGTH) > oend ||
+                                       (op + COPYLENGTH) > oend)
+                               goto _output_error;
                        LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
                        while (op < cpy)
                                *op++ = *ref++;
index 76a1b59..f5907d2 100644 (file)
@@ -279,6 +279,8 @@ int nla_memcpy(void *dest, const struct nlattr *src, int count)
        int minlen = min_t(int, count, nla_len(src));
 
        memcpy(dest, nla_data(src), minlen);
+       if (count > minlen)
+               memset(dest + minlen, 0, count - minlen);
 
        return minlen;
 }
index 626e93d..6817b03 100644 (file)
@@ -1260,6 +1260,7 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        int target_nid, last_cpupid = -1;
        bool page_locked;
        bool migrated = false;
+       bool was_writable;
        int flags = 0;
 
        /* A PROT_NONE fault should not end up here */
@@ -1291,17 +1292,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                flags |= TNF_FAULT_LOCAL;
        }
 
-       /*
-        * Avoid grouping on DSO/COW pages in specific and RO pages
-        * in general, RO pages shouldn't hurt as much anyway since
-        * they can be in shared cache state.
-        *
-        * FIXME! This checks "pmd_dirty()" as an approximation of
-        * "is this a read-only page", since checking "pmd_write()"
-        * is even more broken. We haven't actually turned this into
-        * a writable page, so pmd_write() will always be false.
-        */
-       if (!pmd_dirty(pmd))
+       /* See similar comment in do_numa_page for explanation */
+       if (!(vma->vm_flags & VM_WRITE))
                flags |= TNF_NO_GROUP;
 
        /*
@@ -1358,12 +1350,17 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (migrated) {
                flags |= TNF_MIGRATED;
                page_nid = target_nid;
-       }
+       } else
+               flags |= TNF_MIGRATE_FAIL;
 
        goto out;
 clear_pmdnuma:
        BUG_ON(!PageLocked(page));
+       was_writable = pmd_write(pmd);
        pmd = pmd_modify(pmd, vma->vm_page_prot);
+       pmd = pmd_mkyoung(pmd);
+       if (was_writable)
+               pmd = pmd_mkwrite(pmd);
        set_pmd_at(mm, haddr, pmdp, pmd);
        update_mmu_cache_pmd(vma, addr, pmdp);
        unlock_page(page);
@@ -1487,6 +1484,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
 
        if (__pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
                pmd_t entry;
+               bool preserve_write = prot_numa && pmd_write(*pmd);
                ret = 1;
 
                /*
@@ -1502,9 +1500,11 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                if (!prot_numa || !pmd_protnone(*pmd)) {
                        entry = pmdp_get_and_clear_notify(mm, addr, pmd);
                        entry = pmd_modify(entry, newprot);
+                       if (preserve_write)
+                               entry = pmd_mkwrite(entry);
                        ret = HPAGE_PMD_NR;
                        set_pmd_at(mm, addr, pmd, entry);
-                       BUG_ON(pmd_write(entry));
+                       BUG_ON(!preserve_write && pmd_write(entry));
                }
                spin_unlock(ptl);
        }
index 411144f..97839f5 100644 (file)
@@ -3035,6 +3035,7 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        int last_cpupid;
        int target_nid;
        bool migrated = false;
+       bool was_writable = pte_write(pte);
        int flags = 0;
 
        /* A PROT_NONE fault should not end up here */
@@ -3059,6 +3060,8 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        /* Make it present again */
        pte = pte_modify(pte, vma->vm_page_prot);
        pte = pte_mkyoung(pte);
+       if (was_writable)
+               pte = pte_mkwrite(pte);
        set_pte_at(mm, addr, ptep, pte);
        update_mmu_cache(vma, addr, ptep);
 
@@ -3069,16 +3072,14 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        }
 
        /*
-        * Avoid grouping on DSO/COW pages in specific and RO pages
-        * in general, RO pages shouldn't hurt as much anyway since
-        * they can be in shared cache state.
-        *
-        * FIXME! This checks "pmd_dirty()" as an approximation of
-        * "is this a read-only page", since checking "pmd_write()"
-        * is even more broken. We haven't actually turned this into
-        * a writable page, so pmd_write() will always be false.
+        * Avoid grouping on RO pages in general. RO pages shouldn't hurt as
+        * much anyway since they can be in shared cache state. This misses
+        * the case where a mapping is writable but the process never writes
+        * to it but pte_write gets cleared during protection updates and
+        * pte_dirty has unpredictable behaviour between PTE scan updates,
+        * background writeback, dirty balancing and application behaviour.
         */
-       if (!pte_dirty(pte))
+       if (!(vma->vm_flags & VM_WRITE))
                flags |= TNF_NO_GROUP;
 
        /*
@@ -3102,7 +3103,8 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (migrated) {
                page_nid = target_nid;
                flags |= TNF_MIGRATED;
-       }
+       } else
+               flags |= TNF_MIGRATE_FAIL;
 
 out:
        if (page_nid != -1)
index 9fab107..65842d6 100644 (file)
@@ -1092,6 +1092,10 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
                        return NULL;
 
                arch_refresh_nodedata(nid, pgdat);
+       } else {
+               /* Reset the nr_zones and classzone_idx to 0 before reuse */
+               pgdat->nr_zones = 0;
+               pgdat->classzone_idx = 0;
        }
 
        /* we can use NODE_DATA(nid) from here */
@@ -1977,15 +1981,6 @@ void try_offline_node(int nid)
                if (is_vmalloc_addr(zone->wait_table))
                        vfree(zone->wait_table);
        }
-
-       /*
-        * Since there is no way to guarentee the address of pgdat/zone is not
-        * on stack of any kernel threads or used by other kernel objects
-        * without reference counting or other symchronizing method, do not
-        * reset node_data and free pgdat here. Just reset it to 0 and reuse
-        * the memory when the node is online again.
-        */
-       memset(pgdat, 0, sizeof(*pgdat));
 }
 EXPORT_SYMBOL(try_offline_node);
 
index da9990a..9ec50a3 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -774,10 +774,8 @@ again:                     remove_next = 1 + (end > next->vm_end);
 
                        importer->anon_vma = exporter->anon_vma;
                        error = anon_vma_clone(importer, exporter);
-                       if (error) {
-                               importer->anon_vma = NULL;
+                       if (error)
                                return error;
-                       }
                }
        }
 
index 4472781..8858483 100644 (file)
@@ -75,6 +75,7 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                oldpte = *pte;
                if (pte_present(oldpte)) {
                        pte_t ptent;
+                       bool preserve_write = prot_numa && pte_write(oldpte);
 
                        /*
                         * Avoid trapping faults against the zero or KSM
@@ -94,6 +95,8 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 
                        ptent = ptep_modify_prot_start(mm, addr, pte);
                        ptent = pte_modify(ptent, newprot);
+                       if (preserve_write)
+                               ptent = pte_mkwrite(ptent);
 
                        /* Avoid taking write faults for known dirty pages */
                        if (dirty_accountable && pte_dirty(ptent) &&
index 45e187b..644bcb6 100644 (file)
@@ -857,8 +857,11 @@ static void bdi_update_write_bandwidth(struct backing_dev_info *bdi,
         *                   bw * elapsed + write_bandwidth * (period - elapsed)
         * write_bandwidth = ---------------------------------------------------
         *                                          period
+        *
+        * @written may have decreased due to account_page_redirty().
+        * Avoid underflowing @bw calculation.
         */
-       bw = written - bdi->written_stamp;
+       bw = written - min(written, bdi->written_stamp);
        bw *= HZ;
        if (unlikely(elapsed > period)) {
                do_div(bw, elapsed);
@@ -922,7 +925,7 @@ static void global_update_bandwidth(unsigned long thresh,
                                    unsigned long now)
 {
        static DEFINE_SPINLOCK(dirty_lock);
-       static unsigned long update_time;
+       static unsigned long update_time = INITIAL_JIFFIES;
 
        /*
         * check locklessly first to optimize away locking for the most time
index 72f5ac3..755a42c 100644 (file)
@@ -103,6 +103,7 @@ void unset_migratetype_isolate(struct page *page, unsigned migratetype)
 
                        if (!is_migrate_isolate_page(buddy)) {
                                __isolate_free_page(page, order);
+                               kernel_map_pages(page, (1 << order), 1);
                                set_page_refcounted(page);
                                isolated_page = page;
                        }
index 75c1f28..29f2f8b 100644 (file)
@@ -265,8 +265,15 @@ int walk_page_range(unsigned long start, unsigned long end,
                        vma = vma->vm_next;
 
                        err = walk_page_test(start, next, walk);
-                       if (err > 0)
+                       if (err > 0) {
+                               /*
+                                * positive return values are purely for
+                                * controlling the pagewalk, so should never
+                                * be passed to the callers.
+                                */
+                               err = 0;
                                continue;
+                       }
                        if (err < 0)
                                break;
                }
index 5e3e090..c161a14 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -287,6 +287,13 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
        return 0;
 
  enomem_failure:
+       /*
+        * dst->anon_vma is dropped here otherwise its degree can be incorrectly
+        * decremented in unlink_anon_vmas().
+        * We can safely do this because callers of anon_vma_clone() don't care
+        * about dst->anon_vma if anon_vma_clone() failed.
+        */
+       dst->anon_vma = NULL;
        unlink_anon_vmas(dst);
        return -ENOMEM;
 }
index 6832c4e..82c4737 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2449,7 +2449,8 @@ redo:
        do {
                tid = this_cpu_read(s->cpu_slab->tid);
                c = raw_cpu_ptr(s->cpu_slab);
-       } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid));
+       } while (IS_ENABLED(CONFIG_PREEMPT) &&
+                unlikely(tid != READ_ONCE(c->tid)));
 
        /*
         * Irqless object alloc/free algorithm used here depends on sequence
@@ -2718,7 +2719,8 @@ redo:
        do {
                tid = this_cpu_read(s->cpu_slab->tid);
                c = raw_cpu_ptr(s->cpu_slab);
-       } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid));
+       } while (IS_ENABLED(CONFIG_PREEMPT) &&
+                unlikely(tid != READ_ONCE(c->tid)));
 
        /* Same with comment on barrier() in slab_alloc_node() */
        barrier();
index d8e376a..36a1a73 100644 (file)
@@ -658,14 +658,30 @@ p9_virtio_create(struct p9_client *client, const char *devname, char *args)
 static void p9_virtio_remove(struct virtio_device *vdev)
 {
        struct virtio_chan *chan = vdev->priv;
-
-       if (chan->inuse)
-               p9_virtio_close(chan->client);
-       vdev->config->del_vqs(vdev);
+       unsigned long warning_time;
 
        mutex_lock(&virtio_9p_lock);
+
+       /* Remove self from list so we don't get new users. */
        list_del(&chan->chan_list);
+       warning_time = jiffies;
+
+       /* Wait for existing users to close. */
+       while (chan->inuse) {
+               mutex_unlock(&virtio_9p_lock);
+               msleep(250);
+               if (time_after(jiffies, warning_time + 10 * HZ)) {
+                       dev_emerg(&vdev->dev,
+                                 "p9_virtio_remove: waiting for device in use.\n");
+                       warning_time = jiffies;
+               }
+               mutex_lock(&virtio_9p_lock);
+       }
+
        mutex_unlock(&virtio_9p_lock);
+
+       vdev->config->del_vqs(vdev);
+
        sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
        kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
        kfree(chan->tag);
index b087d27..1849d96 100644 (file)
@@ -563,6 +563,8 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
         */
        del_nbp(p);
 
+       dev_set_mtu(br->dev, br_min_mtu(br));
+
        spin_lock_bh(&br->lock);
        changed_addr = br_stp_recalculate_bridge_id(br);
        spin_unlock_bh(&br->lock);
index 769b185..a6e2da0 100644 (file)
@@ -281,7 +281,7 @@ static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
        int copylen;
 
        ret = -EOPNOTSUPP;
-       if (m->msg_flags&MSG_OOB)
+       if (flags & MSG_OOB)
                goto read_error;
 
        skb = skb_recv_datagram(sk, flags, 0 , &ret);
index 94d3d5e..f7bd286 100644 (file)
@@ -49,6 +49,13 @@ ssize_t get_compat_msghdr(struct msghdr *kmsg,
            __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
            __get_user(kmsg->msg_flags, &umsg->msg_flags))
                return -EFAULT;
+
+       if (!uaddr)
+               kmsg->msg_namelen = 0;
+
+       if (kmsg->msg_namelen < 0)
+               return -EINVAL;
+
        if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
        kmsg->msg_control = compat_ptr(tmp3);
index 962ee9d..45109b7 100644 (file)
@@ -2848,7 +2848,9 @@ static void skb_update_prio(struct sk_buff *skb)
 #define skb_update_prio(skb)
 #endif
 
-static DEFINE_PER_CPU(int, xmit_recursion);
+DEFINE_PER_CPU(int, xmit_recursion);
+EXPORT_SYMBOL(xmit_recursion);
+
 #define RECURSION_LIMIT 10
 
 /**
index 44706e8..e4fdc9d 100644 (file)
@@ -175,9 +175,9 @@ void fib_rules_unregister(struct fib_rules_ops *ops)
 
        spin_lock(&net->rules_mod_lock);
        list_del_rcu(&ops->list);
-       fib_rules_cleanup_ops(ops);
        spin_unlock(&net->rules_mod_lock);
 
+       fib_rules_cleanup_ops(ops);
        call_rcu(&ops->rcu, fib_rules_put_rcu);
 }
 EXPORT_SYMBOL_GPL(fib_rules_unregister);
index cb5290b..70d3450 100644 (file)
@@ -198,8 +198,10 @@ static int __peernet2id(struct net *net, struct net *peer, bool alloc)
  */
 int peernet2id(struct net *net, struct net *peer)
 {
-       int id = __peernet2id(net, peer, true);
+       bool alloc = atomic_read(&peer->count) == 0 ? false : true;
+       int id;
 
+       id = __peernet2id(net, peer, alloc);
        return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED;
 }
 EXPORT_SYMBOL(peernet2id);
index 25b4b5d..7ebed55 100644 (file)
@@ -1932,10 +1932,10 @@ static int rtnl_group_changelink(const struct sk_buff *skb,
                struct ifinfomsg *ifm,
                struct nlattr **tb)
 {
-       struct net_device *dev;
+       struct net_device *dev, *aux;
        int err;
 
-       for_each_netdev(net, dev) {
+       for_each_netdev_safe(net, dev, aux) {
                if (dev->group == group) {
                        err = do_setlink(skb, dev, ifm, tb, NULL, 0);
                        if (err < 0)
@@ -2166,28 +2166,28 @@ replay:
                        }
                }
                err = rtnl_configure_link(dev, ifm);
-               if (err < 0) {
-                       if (ops->newlink) {
-                               LIST_HEAD(list_kill);
-
-                               ops->dellink(dev, &list_kill);
-                               unregister_netdevice_many(&list_kill);
-                       } else {
-                               unregister_netdevice(dev);
-                       }
-                       goto out;
-               }
-
+               if (err < 0)
+                       goto out_unregister;
                if (link_net) {
                        err = dev_change_net_namespace(dev, dest_net, ifname);
                        if (err < 0)
-                               unregister_netdevice(dev);
+                               goto out_unregister;
                }
 out:
                if (link_net)
                        put_net(link_net);
                put_net(dest_net);
                return err;
+out_unregister:
+               if (ops->newlink) {
+                       LIST_HEAD(list_kill);
+
+                       ops->dellink(dev, &list_kill);
+                       unregister_netdevice_many(&list_kill);
+               } else {
+                       unregister_netdevice(dev);
+               }
+               goto out;
        }
 }
 
index f805078..8e4ac97 100644 (file)
@@ -3733,9 +3733,13 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb,
                     struct sock *sk, int tstype)
 {
        struct sk_buff *skb;
-       bool tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
+       bool tsonly;
 
-       if (!sk || !skb_may_tx_timestamp(sk, tsonly))
+       if (!sk)
+               return;
+
+       tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
+       if (!skb_may_tx_timestamp(sk, tsonly))
                return;
 
        if (tsonly)
@@ -4173,7 +4177,7 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
        skb->ignore_df = 0;
        skb_dst_drop(skb);
        skb->mark = 0;
-       skb->sender_cpu = 0;
+       skb_sender_cpu_clear(skb);
        skb_init_secmark(skb);
        secpath_reset(skb);
        nf_reset(skb);
index 93c8b20..71e3e5f 100644 (file)
@@ -653,6 +653,25 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool)
                sock_reset_flag(sk, bit);
 }
 
+bool sk_mc_loop(struct sock *sk)
+{
+       if (dev_recursion_level())
+               return false;
+       if (!sk)
+               return true;
+       switch (sk->sk_family) {
+       case AF_INET:
+               return inet_sk(sk)->mc_loop;
+#if IS_ENABLED(CONFIG_IPV6)
+       case AF_INET6:
+               return inet6_sk(sk)->mc_loop;
+#endif
+       }
+       WARN_ON(1);
+       return true;
+}
+EXPORT_SYMBOL(sk_mc_loop);
+
 /*
  *     This is meant for all protocols to use and covers goings on
  *     at the socket level. Everything here is generic.
@@ -1655,6 +1674,10 @@ void sock_rfree(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_rfree);
 
+/*
+ * Buffer destructor for skbs that are not used directly in read or write
+ * path, e.g. for error handler skbs. Automatically called from kfree_skb.
+ */
 void sock_efree(struct sk_buff *skb)
 {
        sock_put(skb->sk);
index 4334248..8ce351f 100644 (file)
@@ -25,6 +25,8 @@
 static int zero = 0;
 static int one = 1;
 static int ushort_max = USHRT_MAX;
+static int min_sndbuf = SOCK_MIN_SNDBUF;
+static int min_rcvbuf = SOCK_MIN_RCVBUF;
 
 static int net_msg_warn;       /* Unused, but still a sysctl */
 
@@ -237,7 +239,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_sndbuf,
        },
        {
                .procname       = "rmem_max",
@@ -245,7 +247,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_rcvbuf,
        },
        {
                .procname       = "wmem_default",
@@ -253,7 +255,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_sndbuf,
        },
        {
                .procname       = "rmem_default",
@@ -261,7 +263,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_rcvbuf,
        },
        {
                .procname       = "dev_weight",
index faf7cc3..9d66a0f 100644 (file)
@@ -248,7 +248,9 @@ void __init dn_fib_rules_init(void)
 
 void __exit dn_fib_rules_cleanup(void)
 {
+       rtnl_lock();
        fib_rules_unregister(dn_fib_rules_ops);
+       rtnl_unlock();
        rcu_barrier();
 }
 
index 2173402..4dea2e0 100644 (file)
@@ -501,12 +501,10 @@ static struct net_device *dev_to_net_device(struct device *dev)
 #ifdef CONFIG_OF
 static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
                                        struct dsa_chip_data *cd,
-                                       int chip_index,
+                                       int chip_index, int port_index,
                                        struct device_node *link)
 {
-       int ret;
        const __be32 *reg;
-       int link_port_addr;
        int link_sw_addr;
        struct device_node *parent_sw;
        int len;
@@ -519,6 +517,10 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
        if (!reg || (len != sizeof(*reg) * 2))
                return -EINVAL;
 
+       /*
+        * Get the destination switch number from the second field of its 'reg'
+        * property, i.e. for "reg = <0x19 1>" sw_addr is '1'.
+        */
        link_sw_addr = be32_to_cpup(reg + 1);
 
        if (link_sw_addr >= pd->nr_chips)
@@ -535,20 +537,9 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
                memset(cd->rtable, -1, pd->nr_chips * sizeof(s8));
        }
 
-       reg = of_get_property(link, "reg", NULL);
-       if (!reg) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       link_port_addr = be32_to_cpup(reg);
-
-       cd->rtable[link_sw_addr] = link_port_addr;
+       cd->rtable[link_sw_addr] = port_index;
 
        return 0;
-out:
-       kfree(cd->rtable);
-       return ret;
 }
 
 static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
@@ -658,7 +649,7 @@ static int dsa_of_probe(struct platform_device *pdev)
                        if (!strcmp(port_name, "dsa") && link &&
                                        pd->nr_chips > 1) {
                                ret = dsa_of_setup_routing_table(pd, cd,
-                                               chip_index, link);
+                                               chip_index, port_index, link);
                                if (ret)
                                        goto out_free_chip;
                        }
index 57be71d..23b9b3e 100644 (file)
@@ -1111,11 +1111,10 @@ static void ip_fib_net_exit(struct net *net)
 {
        unsigned int i;
 
+       rtnl_lock();
 #ifdef CONFIG_IP_MULTIPLE_TABLES
        fib4_rules_exit(net);
 #endif
-
-       rtnl_lock();
        for (i = 0; i < FIB_TABLE_HASHSZ; i++) {
                struct fib_table *tb;
                struct hlist_head *head;
index 14d02ea..3e44b9b 100644 (file)
@@ -268,6 +268,7 @@ static int inet_csk_wait_for_connect(struct sock *sk, long timeo)
                release_sock(sk);
                if (reqsk_queue_empty(&icsk->icsk_accept_queue))
                        timeo = schedule_timeout(timeo);
+               sched_annotate_sleep();
                lock_sock(sk);
                err = 0;
                if (!reqsk_queue_empty(&icsk->icsk_accept_queue))
index 81751f1..592aff3 100644 (file)
@@ -71,6 +71,20 @@ static inline void inet_diag_unlock_handler(
        mutex_unlock(&inet_diag_table_mutex);
 }
 
+static size_t inet_sk_attr_size(void)
+{
+       return    nla_total_size(sizeof(struct tcp_info))
+               + nla_total_size(1) /* INET_DIAG_SHUTDOWN */
+               + nla_total_size(1) /* INET_DIAG_TOS */
+               + nla_total_size(1) /* INET_DIAG_TCLASS */
+               + nla_total_size(sizeof(struct inet_diag_meminfo))
+               + nla_total_size(sizeof(struct inet_diag_msg))
+               + nla_total_size(SK_MEMINFO_VARS * sizeof(u32))
+               + nla_total_size(TCP_CA_NAME_MAX)
+               + nla_total_size(sizeof(struct tcpvegas_info))
+               + 64;
+}
+
 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
                              struct sk_buff *skb, struct inet_diag_req_v2 *req,
                              struct user_namespace *user_ns,                   
@@ -326,9 +340,7 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s
        if (err)
                goto out;
 
-       rep = nlmsg_new(sizeof(struct inet_diag_msg) +
-                       sizeof(struct inet_diag_meminfo) +
-                       sizeof(struct tcp_info) + 64, GFP_KERNEL);
+       rep = nlmsg_new(inet_sk_attr_size(), GFP_KERNEL);
        if (!rep) {
                err = -ENOMEM;
                goto out;
index 787b3c2..d9bc28a 100644 (file)
@@ -67,6 +67,7 @@ static int ip_forward_finish(struct sk_buff *skb)
        if (unlikely(opt->optlen))
                ip_forward_options(skb);
 
+       skb_sender_cpu_clear(skb);
        return dst_output(skb);
 }
 
index 9d78427..fe54eba 100644 (file)
@@ -268,7 +268,7 @@ static int __net_init ipmr_rules_init(struct net *net)
        return 0;
 
 err2:
-       kfree(mrt);
+       ipmr_free_table(mrt);
 err1:
        fib_rules_unregister(ops);
        return err;
@@ -278,11 +278,13 @@ static void __net_exit ipmr_rules_exit(struct net *net)
 {
        struct mr_table *mrt, *next;
 
+       rtnl_lock();
        list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) {
                list_del(&mrt->list);
                ipmr_free_table(mrt);
        }
        fib_rules_unregister(net->ipv4.mr_rules_ops);
+       rtnl_unlock();
 }
 #else
 #define ipmr_for_each_table(mrt, net) \
@@ -308,7 +310,10 @@ static int __net_init ipmr_rules_init(struct net *net)
 
 static void __net_exit ipmr_rules_exit(struct net *net)
 {
+       rtnl_lock();
        ipmr_free_table(net->ipv4.mrt);
+       net->ipv4.mrt = NULL;
+       rtnl_unlock();
 }
 #endif
 
index 99e810f..cf5e82f 100644 (file)
@@ -272,9 +272,9 @@ static void trace_packet(const struct sk_buff *skb,
                    &chainname, &comment, &rulenum) != 0)
                        break;
 
-       nf_log_packet(net, AF_INET, hook, skb, in, out, &trace_loginfo,
-                     "TRACE: %s:%s:%s:%u ",
-                     tablename, chainname, comment, rulenum);
+       nf_log_trace(net, AF_INET, hook, skb, in, out, &trace_loginfo,
+                    "TRACE: %s:%s:%s:%u ",
+                    tablename, chainname, comment, rulenum);
 }
 #endif
 
index d694088..62856e1 100644 (file)
@@ -378,6 +378,12 @@ EXPORT_SYMBOL_GPL(tcp_slow_start);
  */
 void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked)
 {
+       /* If credits accumulated at a higher w, apply them gently now. */
+       if (tp->snd_cwnd_cnt >= w) {
+               tp->snd_cwnd_cnt = 0;
+               tp->snd_cwnd++;
+       }
+
        tp->snd_cwnd_cnt += acked;
        if (tp->snd_cwnd_cnt >= w) {
                u32 delta = tp->snd_cwnd_cnt / w;
index 4b276d1..06d3d66 100644 (file)
@@ -306,8 +306,10 @@ tcp_friendliness:
                }
        }
 
-       if (ca->cnt == 0)                       /* cannot be zero */
-               ca->cnt = 1;
+       /* The maximum rate of cwnd increase CUBIC allows is 1 packet per
+        * 2 packets ACKed, meaning cwnd grows at 1.5x per RTT.
+        */
+       ca->cnt = max(ca->cnt, 2U);
 }
 
 static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
index fb4cf8b..f501ac0 100644 (file)
@@ -3105,10 +3105,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                        if (!first_ackt.v64)
                                first_ackt = last_ackt;
 
-                       if (!(sacked & TCPCB_SACKED_ACKED))
+                       if (!(sacked & TCPCB_SACKED_ACKED)) {
                                reord = min(pkts_acked, reord);
-                       if (!after(scb->end_seq, tp->high_seq))
-                               flag |= FLAG_ORIG_SACK_ACKED;
+                               if (!after(scb->end_seq, tp->high_seq))
+                                       flag |= FLAG_ORIG_SACK_ACKED;
+                       }
                }
 
                if (sacked & TCPCB_SACKED_ACKED)
index 5a2dfed..f1756ee 100644 (file)
@@ -1518,7 +1518,7 @@ void tcp_v4_early_demux(struct sk_buff *skb)
                skb->sk = sk;
                skb->destructor = sock_edemux;
                if (sk->sk_state != TCP_TIME_WAIT) {
-                       struct dst_entry *dst = sk->sk_rx_dst;
+                       struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);
 
                        if (dst)
                                dst = dst_check(dst, 0);
index a2a796c..1db253e 100644 (file)
@@ -2773,15 +2773,11 @@ void tcp_send_fin(struct sock *sk)
        } else {
                /* Socket is locked, keep trying until memory is available. */
                for (;;) {
-                       skb = alloc_skb_fclone(MAX_TCP_HEADER,
-                                              sk->sk_allocation);
+                       skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation);
                        if (skb)
                                break;
                        yield();
                }
-
-               /* Reserve space for headers and prepare control bits. */
-               skb_reserve(skb, MAX_TCP_HEADER);
                /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
                tcp_init_nondata_skb(skb, tp->write_seq,
                                     TCPHDR_ACK | TCPHDR_FIN);
index d5f6bd9..dab7381 100644 (file)
@@ -63,6 +63,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
                return err;
 
        IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
+       skb->protocol = htons(ETH_P_IP);
 
        return x->outer_mode->output2(x, skb);
 }
@@ -71,7 +72,6 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
 int xfrm4_output_finish(struct sk_buff *skb)
 {
        memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-       skb->protocol = htons(ETH_P_IP);
 
 #ifdef CONFIG_NETFILTER
        IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
index b4d5e1d..70bc6ab 100644 (file)
@@ -104,6 +104,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
                                goto again;
                        flp6->saddr = saddr;
                }
+               err = rt->dst.error;
                goto out;
        }
 again:
@@ -321,7 +322,9 @@ out_fib6_rules_ops:
 
 static void __net_exit fib6_rules_net_exit(struct net *net)
 {
+       rtnl_lock();
        fib_rules_unregister(net->ipv6.fib6_rules_ops);
+       rtnl_unlock();
 }
 
 static struct pernet_operations fib6_rules_net_ops = {
index 0a04a37..36cf0ab 100644 (file)
@@ -318,6 +318,7 @@ static int ip6_forward_proxy_check(struct sk_buff *skb)
 
 static inline int ip6_forward_finish(struct sk_buff *skb)
 {
+       skb_sender_cpu_clear(skb);
        return dst_output(skb);
 }
 
@@ -541,7 +542,8 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
        struct sk_buff *frag;
        struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
-       struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
+       struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
+                               inet6_sk(skb->sk) : NULL;
        struct ipv6hdr *tmp_hdr;
        struct frag_hdr *fh;
        unsigned int mtu, hlen, left, len;
index 266a264..ddd94ec 100644 (file)
@@ -314,7 +314,7 @@ out:
  *   Create tunnel matching given parameters.
  *
  * Return:
- *   created tunnel or NULL
+ *   created tunnel or error pointer
  **/
 
 static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
@@ -322,7 +322,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
        struct net_device *dev;
        struct ip6_tnl *t;
        char name[IFNAMSIZ];
-       int err;
+       int err = -ENOMEM;
 
        if (p->name[0])
                strlcpy(name, p->name, IFNAMSIZ);
@@ -348,7 +348,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
 failed_free:
        ip6_dev_free(dev);
 failed:
-       return NULL;
+       return ERR_PTR(err);
 }
 
 /**
@@ -362,7 +362,7 @@ failed:
  *   tunnel device is created and registered for use.
  *
  * Return:
- *   matching tunnel or NULL
+ *   matching tunnel or error pointer
  **/
 
 static struct ip6_tnl *ip6_tnl_locate(struct net *net,
@@ -380,13 +380,13 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net,
                if (ipv6_addr_equal(local, &t->parms.laddr) &&
                    ipv6_addr_equal(remote, &t->parms.raddr)) {
                        if (create)
-                               return NULL;
+                               return ERR_PTR(-EEXIST);
 
                        return t;
                }
        }
        if (!create)
-               return NULL;
+               return ERR_PTR(-ENODEV);
        return ip6_tnl_create(net, p);
 }
 
@@ -1420,7 +1420,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        }
                        ip6_tnl_parm_from_user(&p1, &p);
                        t = ip6_tnl_locate(net, &p1, 0);
-                       if (t == NULL)
+                       if (IS_ERR(t))
                                t = netdev_priv(dev);
                } else {
                        memset(&p, 0, sizeof(p));
@@ -1445,7 +1445,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                ip6_tnl_parm_from_user(&p1, &p);
                t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
                if (cmd == SIOCCHGTUNNEL) {
-                       if (t != NULL) {
+                       if (!IS_ERR(t)) {
                                if (t->dev != dev) {
                                        err = -EEXIST;
                                        break;
@@ -1457,14 +1457,15 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        else
                                err = ip6_tnl_update(t, &p1);
                }
-               if (t) {
+               if (!IS_ERR(t)) {
                        err = 0;
                        ip6_tnl_parm_to_user(&p, &t->parms);
                        if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
                                err = -EFAULT;
 
-               } else
-                       err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+               } else {
+                       err = PTR_ERR(t);
+               }
                break;
        case SIOCDELTUNNEL:
                err = -EPERM;
@@ -1478,7 +1479,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        err = -ENOENT;
                        ip6_tnl_parm_from_user(&p1, &p);
                        t = ip6_tnl_locate(net, &p1, 0);
-                       if (t == NULL)
+                       if (IS_ERR(t))
                                break;
                        err = -EPERM;
                        if (t->dev == ip6n->fb_tnl_dev)
@@ -1672,12 +1673,13 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
                           struct nlattr *tb[], struct nlattr *data[])
 {
        struct net *net = dev_net(dev);
-       struct ip6_tnl *nt;
+       struct ip6_tnl *nt, *t;
 
        nt = netdev_priv(dev);
        ip6_tnl_netlink_parms(data, &nt->parms);
 
-       if (ip6_tnl_locate(net, &nt->parms, 0))
+       t = ip6_tnl_locate(net, &nt->parms, 0);
+       if (!IS_ERR(t))
                return -EEXIST;
 
        return ip6_tnl_create2(dev);
@@ -1697,8 +1699,7 @@ static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
        ip6_tnl_netlink_parms(data, &p);
 
        t = ip6_tnl_locate(net, &p, 0);
-
-       if (t) {
+       if (!IS_ERR(t)) {
                if (t->dev != dev)
                        return -EEXIST;
        } else
index 34b6826..312e0ff 100644 (file)
@@ -252,7 +252,7 @@ static int __net_init ip6mr_rules_init(struct net *net)
        return 0;
 
 err2:
-       kfree(mrt);
+       ip6mr_free_table(mrt);
 err1:
        fib_rules_unregister(ops);
        return err;
@@ -267,8 +267,8 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
                list_del(&mrt->list);
                ip6mr_free_table(mrt);
        }
-       rtnl_unlock();
        fib_rules_unregister(net->ipv6.mr6_rules_ops);
+       rtnl_unlock();
 }
 #else
 #define ip6mr_for_each_table(mrt, net) \
@@ -336,7 +336,7 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
 
 static void ip6mr_free_table(struct mr6_table *mrt)
 {
-       del_timer(&mrt->ipmr_expire_timer);
+       del_timer_sync(&mrt->ipmr_expire_timer);
        mroute_clean_tables(mrt);
        kfree(mrt);
 }
index 471ed24..14ecdaf 100644 (file)
@@ -1218,7 +1218,14 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        if (rt)
                rt6_set_expires(rt, jiffies + (HZ * lifetime));
        if (ra_msg->icmph.icmp6_hop_limit) {
-               in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+               /* Only set hop_limit on the interface if it is higher than
+                * the current hop_limit.
+                */
+               if (in6_dev->cnf.hop_limit < ra_msg->icmph.icmp6_hop_limit) {
+                       in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+               } else {
+                       ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than current\n");
+               }
                if (rt)
                        dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
                                       ra_msg->icmph.icmp6_hop_limit);
index e080fbb..bb00c6f 100644 (file)
@@ -298,9 +298,9 @@ static void trace_packet(const struct sk_buff *skb,
                    &chainname, &comment, &rulenum) != 0)
                        break;
 
-       nf_log_packet(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
-                     "TRACE: %s:%s:%s:%u ",
-                     tablename, chainname, comment, rulenum);
+       nf_log_trace(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
+                    "TRACE: %s:%s:%s:%u ",
+                    tablename, chainname, comment, rulenum);
 }
 #endif
 
index 5d46832..1f5e622 100644 (file)
@@ -1411,6 +1411,15 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr,
        TCP_SKB_CB(skb)->sacked = 0;
 }
 
+static void tcp_v6_restore_cb(struct sk_buff *skb)
+{
+       /* We need to move header back to the beginning if xfrm6_policy_check()
+        * and tcp_v6_fill_cb() are going to be called again.
+        */
+       memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
+               sizeof(struct inet6_skb_parm));
+}
+
 static int tcp_v6_rcv(struct sk_buff *skb)
 {
        const struct tcphdr *th;
@@ -1543,6 +1552,7 @@ do_time_wait:
                        inet_twsk_deschedule(tw, &tcp_death_row);
                        inet_twsk_put(tw);
                        sk = sk2;
+                       tcp_v6_restore_cb(skb);
                        goto process;
                }
                /* Fall through to ACK */
@@ -1551,6 +1561,7 @@ do_time_wait:
                tcp_v6_timewait_ack(sk, skb);
                break;
        case TCP_TW_RST:
+               tcp_v6_restore_cb(skb);
                goto no_tcp_socket;
        case TCP_TW_SUCCESS:
                ;
@@ -1585,7 +1596,7 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
                skb->sk = sk;
                skb->destructor = sock_edemux;
                if (sk->sk_state != TCP_TIME_WAIT) {
-                       struct dst_entry *dst = sk->sk_rx_dst;
+                       struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);
 
                        if (dst)
                                dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
index ab889bb..be2c0ba 100644 (file)
@@ -112,11 +112,9 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
                fptr->nexthdr = nexthdr;
                fptr->reserved = 0;
-               if (skb_shinfo(skb)->ip6_frag_id)
-                       fptr->identification = skb_shinfo(skb)->ip6_frag_id;
-               else
-                       ipv6_select_ident(fptr,
-                                         (struct rt6_info *)skb_dst(skb));
+               if (!skb_shinfo(skb)->ip6_frag_id)
+                       ipv6_proxy_select_ident(skb);
+               fptr->identification = skb_shinfo(skb)->ip6_frag_id;
 
                /* Fragment the skb. ipv6 header and the remaining fields of the
                 * fragment header are updated in ipv6_gso_segment()
index ca3f29b..010f8bd 100644 (file)
@@ -114,6 +114,7 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
                return err;
 
        skb->ignore_df = 1;
+       skb->protocol = htons(ETH_P_IPV6);
 
        return x->outer_mode->output2(x, skb);
 }
@@ -122,7 +123,6 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
 int xfrm6_output_finish(struct sk_buff *skb)
 {
        memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
-       skb->protocol = htons(ETH_P_IPV6);
 
 #ifdef CONFIG_NETFILTER
        IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
index 48bf5a0..8d2d01b 100644 (file)
@@ -200,6 +200,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
 
 #if IS_ENABLED(CONFIG_IPV6_MIP6)
                case IPPROTO_MH:
+                       offset += ipv6_optlen(exthdr);
                        if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
                                struct ip6_mh *mh;
 
index 2e9953b..53d9311 100644 (file)
@@ -1114,10 +1114,8 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        noblock, &err);
        else
                skb = sock_alloc_send_skb(sk, len, noblock, &err);
-       if (!skb) {
-               err = -ENOMEM;
+       if (!skb)
                goto out;
-       }
        if (iucv->transport == AF_IUCV_TRANS_HIPER)
                skb_reserve(skb, sizeof(struct af_iucv_trans_hdr) + ETH_HLEN);
        if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
index 895348e..a29a504 100644 (file)
@@ -1871,6 +1871,7 @@ static int __init l2tp_init(void)
        l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0);
        if (!l2tp_wq) {
                pr_err("alloc_workqueue failed\n");
+               unregister_pernet_device(&l2tp_net_ops);
                rc = -ENOMEM;
                goto out;
        }
index a48bad4..7702978 100644 (file)
@@ -49,8 +49,6 @@ static void ieee80211_free_tid_rx(struct rcu_head *h)
                container_of(h, struct tid_ampdu_rx, rcu_head);
        int i;
 
-       del_timer_sync(&tid_rx->reorder_timer);
-
        for (i = 0; i < tid_rx->buf_size; i++)
                __skb_queue_purge(&tid_rx->reorder_buf[i]);
        kfree(tid_rx->reorder_buf);
@@ -93,6 +91,12 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 
        del_timer_sync(&tid_rx->session_timer);
 
+       /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
+       spin_lock_bh(&tid_rx->reorder_lock);
+       tid_rx->removed = true;
+       spin_unlock_bh(&tid_rx->reorder_lock);
+       del_timer_sync(&tid_rx->reorder_timer);
+
        call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
 }
 
index 3afe368..8d53d65 100644 (file)
@@ -58,13 +58,24 @@ struct ieee80211_local;
 #define IEEE80211_UNSET_POWER_LEVEL    INT_MIN
 
 /*
- * Some APs experience problems when working with U-APSD. Decrease the
- * probability of that happening by using legacy mode for all ACs but VO.
- * The AP that caused us trouble was a Cisco 4410N. It ignores our
- * setting, and always treats non-VO ACs as legacy.
+ * Some APs experience problems when working with U-APSD. Decreasing the
+ * probability of that happening by using legacy mode for all ACs but VO isn't
+ * enough.
+ *
+ * Cisco 4410N originally forced us to enable VO by default only because it
+ * treated non-VO ACs as legacy.
+ *
+ * However some APs (notably Netgear R7000) silently reclassify packets to
+ * different ACs. Since u-APSD ACs require trigger frames for frame retrieval
+ * clients would never see some frames (e.g. ARP responses) or would fetch them
+ * accidentally after a long time.
+ *
+ * It makes little sense to enable u-APSD queues by default because it needs
+ * userspace applications to be aware of it to actually take advantage of the
+ * possible additional powersavings. Implicitly depending on driver autotrigger
+ * frame support doesn't make much sense.
  */
-#define IEEE80211_DEFAULT_UAPSD_QUEUES \
-       IEEE80211_WMM_IE_STA_QOSINFO_AC_VO
+#define IEEE80211_DEFAULT_UAPSD_QUEUES 0
 
 #define IEEE80211_DEFAULT_MAX_SP_LEN           \
        IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
@@ -453,6 +464,7 @@ struct ieee80211_if_managed {
        unsigned int flags;
 
        bool csa_waiting_bcn;
+       bool csa_ignored_same_chan;
 
        bool beacon_crc_valid;
        u32 beacon_crc;
index 10ac632..142f66a 100644 (file)
@@ -1150,6 +1150,17 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
+       if (cfg80211_chandef_identical(&csa_ie.chandef,
+                                      &sdata->vif.bss_conf.chandef)) {
+               if (ifmgd->csa_ignored_same_chan)
+                       return;
+               sdata_info(sdata,
+                          "AP %pM tries to chanswitch to same channel, ignore\n",
+                          ifmgd->associated->bssid);
+               ifmgd->csa_ignored_same_chan = true;
+               return;
+       }
+
        mutex_lock(&local->mtx);
        mutex_lock(&local->chanctx_mtx);
        conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
@@ -1210,6 +1221,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        sdata->vif.csa_active = true;
        sdata->csa_chandef = csa_ie.chandef;
        sdata->csa_block_tx = csa_ie.mode;
+       ifmgd->csa_ignored_same_chan = false;
 
        if (sdata->csa_block_tx)
                ieee80211_stop_vif_queues(local, sdata,
@@ -2090,6 +2102,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        sdata->vif.csa_active = false;
        ifmgd->csa_waiting_bcn = false;
+       ifmgd->csa_ignored_same_chan = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -3204,7 +3217,8 @@ static const u64 care_about_ies =
        (1ULL << WLAN_EID_CHANNEL_SWITCH) |
        (1ULL << WLAN_EID_PWR_CONSTRAINT) |
        (1ULL << WLAN_EID_HT_CAPABILITY) |
-       (1ULL << WLAN_EID_HT_OPERATION);
+       (1ULL << WLAN_EID_HT_OPERATION) |
+       (1ULL << WLAN_EID_EXT_CHANSWITCH_ANN);
 
 static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_mgmt *mgmt, size_t len,
index 1101563..1eb730b 100644 (file)
@@ -873,9 +873,10 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
 
  set_release_timer:
 
-               mod_timer(&tid_agg_rx->reorder_timer,
-                         tid_agg_rx->reorder_time[j] + 1 +
-                         HT_RX_REORDER_BUF_TIMEOUT);
+               if (!tid_agg_rx->removed)
+                       mod_timer(&tid_agg_rx->reorder_timer,
+                                 tid_agg_rx->reorder_time[j] + 1 +
+                                 HT_RX_REORDER_BUF_TIMEOUT);
        } else {
                del_timer(&tid_agg_rx->reorder_timer);
        }
@@ -2214,6 +2215,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        hdr = (struct ieee80211_hdr *) skb->data;
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
 
+       if (ieee80211_drop_unencrypted(rx, hdr->frame_control))
+               return RX_DROP_MONITOR;
+
        /* frame is in RMC, don't forward */
        if (ieee80211_is_data(hdr->frame_control) &&
            is_multicast_ether_addr(hdr->addr1) &&
index 925e68f..fb0fc13 100644 (file)
@@ -175,6 +175,7 @@ struct tid_ampdu_tx {
  * @reorder_lock: serializes access to reorder buffer, see below.
  * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and
  *     and ssn.
+ * @removed: this session is removed (but might have been found due to RCU)
  *
  * This structure's lifetime is managed by RCU, assignments to
  * the array holding it must hold the aggregation mutex.
@@ -199,6 +200,7 @@ struct tid_ampdu_rx {
        u16 timeout;
        u8 dialog_token;
        bool auto_seq;
+       bool removed;
 };
 
 /**
index 8428f4a..747bdcf 100644 (file)
@@ -3178,7 +3178,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
                wdev_iter = &sdata_iter->wdev;
 
                if (sdata_iter == sdata ||
-                   rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL ||
+                   !ieee80211_sdata_running(sdata_iter) ||
                    local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
                        continue;
 
index 0d8448f..675d12c 100644 (file)
@@ -212,6 +212,30 @@ void nf_log_packet(struct net *net,
 }
 EXPORT_SYMBOL(nf_log_packet);
 
+void nf_log_trace(struct net *net,
+                 u_int8_t pf,
+                 unsigned int hooknum,
+                 const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct nf_loginfo *loginfo, const char *fmt, ...)
+{
+       va_list args;
+       char prefix[NF_LOG_PREFIXLEN];
+       const struct nf_logger *logger;
+
+       rcu_read_lock();
+       logger = rcu_dereference(net->nf.nf_loggers[pf]);
+       if (logger) {
+               va_start(args, fmt);
+               vsnprintf(prefix, sizeof(prefix), fmt, args);
+               va_end(args);
+               logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
+       }
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(nf_log_trace);
+
 #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
 
 struct nf_log_buf {
index 6ab7779..ac1a952 100644 (file)
@@ -1225,7 +1225,10 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
 
        if (nla[NFTA_CHAIN_POLICY]) {
                if ((chain != NULL &&
-                   !(chain->flags & NFT_BASE_CHAIN)) ||
+                   !(chain->flags & NFT_BASE_CHAIN)))
+                       return -EOPNOTSUPP;
+
+               if (chain == NULL &&
                    nla[NFTA_CHAIN_HOOK] == NULL)
                        return -EOPNOTSUPP;
 
index 3b90eb2..2d298dc 100644 (file)
@@ -94,10 +94,10 @@ static void nft_trace_packet(const struct nft_pktinfo *pkt,
 {
        struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
 
-       nf_log_packet(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
-                     pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
-                     chain->table->name, chain->name, comments[type],
-                     rulenum);
+       nf_log_trace(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
+                    pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
+                    chain->table->name, chain->name, comments[type],
+                    rulenum);
 }
 
 unsigned int
index a5599fc..54330fb 100644 (file)
@@ -77,6 +77,9 @@ nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
        if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
                return -EINVAL;
 
+       /* Not all fields are initialized so first zero the tuple */
+       memset(tuple, 0, sizeof(struct nf_conntrack_tuple));
+
        tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM]));
        tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
 
index 213584c..65f3e2b 100644 (file)
@@ -133,6 +133,9 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par,
                entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
                break;
        case AF_INET6:
+               if (proto)
+                       entry->e6.ipv6.flags |= IP6T_F_PROTO;
+
                entry->e6.ipv6.proto = proto;
                entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
                break;
@@ -344,6 +347,9 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
                entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
                break;
        case AF_INET6:
+               if (proto)
+                       entry->e6.ipv6.flags |= IP6T_F_PROTO;
+
                entry->e6.ipv6.proto = proto;
                entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
                break;
index c82df0a..37c15e6 100644 (file)
@@ -153,6 +153,8 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
                                iter->err = err;
                                goto out;
                        }
+
+                       continue;
                }
 
                if (iter->count < iter->skip)
index ef8a926..50e1e5a 100644 (file)
@@ -513,8 +513,8 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par)
 {
        const struct ip6t_ip6 *i = par->entryinfo;
 
-       if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
-           && !(i->flags & IP6T_INV_PROTO))
+       if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) &&
+           !(i->invflags & IP6T_INV_PROTO))
                return 0;
 
        pr_info("Can be used only in combination with "
index ec2954f..067a3ff 100644 (file)
@@ -274,10 +274,8 @@ void ovs_vport_del(struct vport *vport)
        ASSERT_OVSL();
 
        hlist_del_rcu(&vport->hash_node);
-
-       vport->ops->destroy(vport);
-
        module_put(vport->ops->owner);
+       vport->ops->destroy(vport);
 }
 
 /**
index a817705..dba8d08 100644 (file)
@@ -88,7 +88,9 @@ static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
                        int *unpinned);
 static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
 
-static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwdev, struct rdma_cm_id **cm_id)
+static int rds_iw_get_device(struct sockaddr_in *src, struct sockaddr_in *dst,
+                            struct rds_iw_device **rds_iwdev,
+                            struct rdma_cm_id **cm_id)
 {
        struct rds_iw_device *iwdev;
        struct rds_iw_cm_id *i_cm_id;
@@ -112,15 +114,15 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
                                src_addr->sin_port,
                                dst_addr->sin_addr.s_addr,
                                dst_addr->sin_port,
-                               rs->rs_bound_addr,
-                               rs->rs_bound_port,
-                               rs->rs_conn_addr,
-                               rs->rs_conn_port);
+                               src->sin_addr.s_addr,
+                               src->sin_port,
+                               dst->sin_addr.s_addr,
+                               dst->sin_port);
 #ifdef WORKING_TUPLE_DETECTION
-                       if (src_addr->sin_addr.s_addr == rs->rs_bound_addr &&
-                           src_addr->sin_port == rs->rs_bound_port &&
-                           dst_addr->sin_addr.s_addr == rs->rs_conn_addr &&
-                           dst_addr->sin_port == rs->rs_conn_port) {
+                       if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr &&
+                           src_addr->sin_port == src->sin_port &&
+                           dst_addr->sin_addr.s_addr == dst->sin_addr.s_addr &&
+                           dst_addr->sin_port == dst->sin_port) {
 #else
                        /* FIXME - needs to compare the local and remote
                         * ipaddr/port tuple, but the ipaddr is the only
@@ -128,7 +130,7 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
                         * zero'ed.  It doesn't appear to be properly populated
                         * during connection setup...
                         */
-                       if (src_addr->sin_addr.s_addr == rs->rs_bound_addr) {
+                       if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr) {
 #endif
                                spin_unlock_irq(&iwdev->spinlock);
                                *rds_iwdev = iwdev;
@@ -180,19 +182,13 @@ int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_i
 {
        struct sockaddr_in *src_addr, *dst_addr;
        struct rds_iw_device *rds_iwdev_old;
-       struct rds_sock rs;
        struct rdma_cm_id *pcm_id;
        int rc;
 
        src_addr = (struct sockaddr_in *)&cm_id->route.addr.src_addr;
        dst_addr = (struct sockaddr_in *)&cm_id->route.addr.dst_addr;
 
-       rs.rs_bound_addr = src_addr->sin_addr.s_addr;
-       rs.rs_bound_port = src_addr->sin_port;
-       rs.rs_conn_addr = dst_addr->sin_addr.s_addr;
-       rs.rs_conn_port = dst_addr->sin_port;
-
-       rc = rds_iw_get_device(&rs, &rds_iwdev_old, &pcm_id);
+       rc = rds_iw_get_device(src_addr, dst_addr, &rds_iwdev_old, &pcm_id);
        if (rc)
                rds_iw_remove_cm_id(rds_iwdev, cm_id);
 
@@ -598,9 +594,17 @@ void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
        struct rds_iw_device *rds_iwdev;
        struct rds_iw_mr *ibmr = NULL;
        struct rdma_cm_id *cm_id;
+       struct sockaddr_in src = {
+               .sin_addr.s_addr = rs->rs_bound_addr,
+               .sin_port = rs->rs_bound_port,
+       };
+       struct sockaddr_in dst = {
+               .sin_addr.s_addr = rs->rs_conn_addr,
+               .sin_port = rs->rs_conn_port,
+       };
        int ret;
 
-       ret = rds_iw_get_device(rs, &rds_iwdev, &cm_id);
+       ret = rds_iw_get_device(&src, &dst, &rds_iwdev, &cm_id);
        if (ret || !cm_id) {
                ret = -ENODEV;
                goto out;
index 4575485..19a5606 100644 (file)
@@ -87,7 +87,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
                if (!skb) {
                        /* nothing remains on the queue */
                        if (copied &&
-                           (msg->msg_flags & MSG_PEEK || timeo == 0))
+                           (flags & MSG_PEEK || timeo == 0))
                                goto out;
 
                        /* wait for a message to turn up */
index 82c5d7f..5f6288f 100644 (file)
@@ -25,21 +25,41 @@ static int tcf_bpf(struct sk_buff *skb, const struct tc_action *a,
                   struct tcf_result *res)
 {
        struct tcf_bpf *b = a->priv;
-       int action;
-       int filter_res;
+       int action, filter_res;
 
        spin_lock(&b->tcf_lock);
+
        b->tcf_tm.lastuse = jiffies;
        bstats_update(&b->tcf_bstats, skb);
-       action = b->tcf_action;
 
        filter_res = BPF_PROG_RUN(b->filter, skb);
-       if (filter_res == 0) {
-               /* Return code 0 from the BPF program
-                * is being interpreted as a drop here.
-                */
-               action = TC_ACT_SHOT;
+
+       /* A BPF program may overwrite the default action opcode.
+        * Similarly as in cls_bpf, if filter_res == -1 we use the
+        * default action specified from tc.
+        *
+        * In case a different well-known TC_ACT opcode has been
+        * returned, it will overwrite the default one.
+        *
+        * For everything else that is unkown, TC_ACT_UNSPEC is
+        * returned.
+        */
+       switch (filter_res) {
+       case TC_ACT_PIPE:
+       case TC_ACT_RECLASSIFY:
+       case TC_ACT_OK:
+               action = filter_res;
+               break;
+       case TC_ACT_SHOT:
+               action = filter_res;
                b->tcf_qstats.drops++;
+               break;
+       case TC_ACT_UNSPEC:
+               action = b->tcf_action;
+               break;
+       default:
+               action = TC_ACT_UNSPEC;
+               break;
        }
 
        spin_unlock(&b->tcf_lock);
index 09487af..95fdf4e 100644 (file)
@@ -78,8 +78,11 @@ struct tc_u_hnode {
        struct tc_u_common      *tp_c;
        int                     refcnt;
        unsigned int            divisor;
-       struct tc_u_knode __rcu *ht[1];
        struct rcu_head         rcu;
+       /* The 'ht' field MUST be the last field in structure to allow for
+        * more entries allocated at end of structure.
+        */
+       struct tc_u_knode __rcu *ht[1];
 };
 
 struct tc_u_common {
index bbedbfc..245330c 100644 (file)
@@ -1702,6 +1702,8 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
 
        if (len > INT_MAX)
                len = INT_MAX;
+       if (unlikely(!access_ok(VERIFY_READ, buff, len)))
+               return -EFAULT;
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
@@ -1760,6 +1762,8 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
 
        if (size > INT_MAX)
                size = INT_MAX;
+       if (unlikely(!access_ok(VERIFY_WRITE, ubuf, size)))
+               return -EFAULT;
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
index 612aa73..e6ce151 100644 (file)
@@ -303,9 +303,7 @@ static int rpc_client_register(struct rpc_clnt *clnt,
        struct super_block *pipefs_sb;
        int err;
 
-       err = rpc_clnt_debugfs_register(clnt);
-       if (err)
-               return err;
+       rpc_clnt_debugfs_register(clnt);
 
        pipefs_sb = rpc_get_sb_net(net);
        if (pipefs_sb) {
index e811f39..82962f7 100644 (file)
@@ -129,48 +129,52 @@ static const struct file_operations tasks_fops = {
        .release        = tasks_release,
 };
 
-int
+void
 rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
 {
-       int len, err;
+       int len;
        char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */
+       struct rpc_xprt *xprt;
 
        /* Already registered? */
-       if (clnt->cl_debugfs)
-               return 0;
+       if (clnt->cl_debugfs || !rpc_clnt_dir)
+               return;
 
        len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
        if (len >= sizeof(name))
-               return -EINVAL;
+               return;
 
        /* make the per-client dir */
        clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir);
        if (!clnt->cl_debugfs)
-               return -ENOMEM;
+               return;
 
        /* make tasks file */
-       err = -ENOMEM;
        if (!debugfs_create_file("tasks", S_IFREG | S_IRUSR, clnt->cl_debugfs,
                                 clnt, &tasks_fops))
                goto out_err;
 
-       err = -EINVAL;
        rcu_read_lock();
+       xprt = rcu_dereference(clnt->cl_xprt);
+       /* no "debugfs" dentry? Don't bother with the symlink. */
+       if (!xprt->debugfs) {
+               rcu_read_unlock();
+               return;
+       }
        len = snprintf(name, sizeof(name), "../../rpc_xprt/%s",
-                       rcu_dereference(clnt->cl_xprt)->debugfs->d_name.name);
+                       xprt->debugfs->d_name.name);
        rcu_read_unlock();
+
        if (len >= sizeof(name))
                goto out_err;
 
-       err = -ENOMEM;
        if (!debugfs_create_symlink("xprt", clnt->cl_debugfs, name))
                goto out_err;
 
-       return 0;
+       return;
 out_err:
        debugfs_remove_recursive(clnt->cl_debugfs);
        clnt->cl_debugfs = NULL;
-       return err;
 }
 
 void
@@ -226,33 +230,33 @@ static const struct file_operations xprt_info_fops = {
        .release        = xprt_info_release,
 };
 
-int
+void
 rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
 {
        int len, id;
        static atomic_t cur_id;
        char            name[9]; /* 8 hex digits + NULL term */
 
+       if (!rpc_xprt_dir)
+               return;
+
        id = (unsigned int)atomic_inc_return(&cur_id);
 
        len = snprintf(name, sizeof(name), "%x", id);
        if (len >= sizeof(name))
-               return -EINVAL;
+               return;
 
        /* make the per-client dir */
        xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir);
        if (!xprt->debugfs)
-               return -ENOMEM;
+               return;
 
        /* make tasks file */
        if (!debugfs_create_file("info", S_IFREG | S_IRUSR, xprt->debugfs,
                                 xprt, &xprt_info_fops)) {
                debugfs_remove_recursive(xprt->debugfs);
                xprt->debugfs = NULL;
-               return -ENOMEM;
        }
-
-       return 0;
 }
 
 void
@@ -266,14 +270,17 @@ void __exit
 sunrpc_debugfs_exit(void)
 {
        debugfs_remove_recursive(topdir);
+       topdir = NULL;
+       rpc_clnt_dir = NULL;
+       rpc_xprt_dir = NULL;
 }
 
-int __init
+void __init
 sunrpc_debugfs_init(void)
 {
        topdir = debugfs_create_dir("sunrpc", NULL);
        if (!topdir)
-               goto out;
+               return;
 
        rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir);
        if (!rpc_clnt_dir)
@@ -283,10 +290,9 @@ sunrpc_debugfs_init(void)
        if (!rpc_xprt_dir)
                goto out_remove;
 
-       return 0;
+       return;
 out_remove:
        debugfs_remove_recursive(topdir);
        topdir = NULL;
-out:
-       return -ENOMEM;
+       rpc_clnt_dir = NULL;
 }
index e37fbed..ee5d3d2 100644 (file)
@@ -98,10 +98,7 @@ init_sunrpc(void)
        if (err)
                goto out4;
 
-       err = sunrpc_debugfs_init();
-       if (err)
-               goto out5;
-
+       sunrpc_debugfs_init();
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
        rpc_register_sysctl();
 #endif
@@ -109,8 +106,6 @@ init_sunrpc(void)
        init_socket_xprt();     /* clnt sock transport */
        return 0;
 
-out5:
-       unregister_rpc_pipefs();
 out4:
        unregister_pernet_subsys(&sunrpc_net_ops);
 out3:
index e3015ae..9949722 100644 (file)
@@ -1331,7 +1331,6 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net)
  */
 struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
 {
-       int err;
        struct rpc_xprt *xprt;
        struct xprt_class *t;
 
@@ -1372,11 +1371,7 @@ found:
                return ERR_PTR(-ENOMEM);
        }
 
-       err = rpc_xprt_debugfs_register(xprt);
-       if (err) {
-               xprt_destroy(xprt);
-               return ERR_PTR(err);
-       }
+       rpc_xprt_debugfs_register(xprt);
 
        dprintk("RPC:       created transport %p with %u slots\n", xprt,
                        xprt->max_reqs);
index 935205e..be1c9fa 100644 (file)
@@ -152,11 +152,11 @@ out_netlink:
 static void __exit tipc_exit(void)
 {
        tipc_bearer_cleanup();
+       unregister_pernet_subsys(&tipc_net_ops);
        tipc_netlink_stop();
        tipc_netlink_compat_stop();
        tipc_socket_stop();
        tipc_unregister_sysctl();
-       unregister_pernet_subsys(&tipc_net_ops);
 
        pr_info("Deactivated\n");
 }
index be25015..b6f84f6 100644 (file)
@@ -4400,6 +4400,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
+       /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
+        * as userspace might just pass through the capabilities from the IEs
+        * directly, rather than enforcing this restriction and returning an
+        * error in this case.
+        */
+       if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
+               params.ht_capa = NULL;
+               params.vht_capa = NULL;
+       }
+
        /* When you run into this, adjust the code below for the new flag */
        BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
 
index cee479b..638af06 100644 (file)
@@ -2269,11 +2269,9 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
                 * have the xfrm_state's. We need to wait for KM to
                 * negotiate new SA's or bail out with error.*/
                if (net->xfrm.sysctl_larval_drop) {
-                       dst_release(dst);
-                       xfrm_pols_put(pols, drop_pols);
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
-
-                       return ERR_PTR(-EREMOTE);
+                       err = -EREMOTE;
+                       goto error;
                }
 
                err = -EAGAIN;
@@ -2324,7 +2322,8 @@ nopol:
 error:
        dst_release(dst);
 dropdst:
-       dst_release(dst_orig);
+       if (!(flags & XFRM_LOOKUP_KEEP_DST_REF))
+               dst_release(dst_orig);
        xfrm_pols_put(pols, drop_pols);
        return ERR_PTR(err);
 }
@@ -2338,7 +2337,8 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
                                    struct sock *sk, int flags)
 {
        struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk,
-                                           flags | XFRM_LOOKUP_QUEUE);
+                                           flags | XFRM_LOOKUP_QUEUE |
+                                           XFRM_LOOKUP_KEEP_DST_REF);
 
        if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
                return make_blackhole(net, dst_orig->ops->family, dst_orig);
index 1684bcc..5fde343 100644 (file)
@@ -152,7 +152,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
                goto out;
 
        /* No partial writes. */
-       length = EINVAL;
+       length = -EINVAL;
        if (*ppos != 0)
                goto out;
 
index fe18071..8ec5289 100644 (file)
@@ -687,13 +687,30 @@ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
        return val;
 }
 
+/* is this a stereo widget or a stereo-to-mono mix? */
+static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir)
+{
+       unsigned int wcaps = get_wcaps(codec, nid);
+       hda_nid_t conn;
+
+       if (wcaps & AC_WCAP_STEREO)
+               return true;
+       if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
+               return false;
+       if (snd_hda_get_num_conns(codec, nid) != 1)
+               return false;
+       if (snd_hda_get_connections(codec, nid, &conn, 1) < 0)
+               return false;
+       return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO);
+}
+
 /* initialize the amp value (only at the first time) */
 static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
 {
        unsigned int caps = query_amp_caps(codec, nid, dir);
        int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
 
-       if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
+       if (is_stereo_amps(codec, nid, dir))
                snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
        else
                snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
@@ -703,7 +720,7 @@ static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
 static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
                      unsigned int mask, unsigned int val)
 {
-       if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
+       if (is_stereo_amps(codec, nid, dir))
                return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
                                                mask, val);
        else
index 4ca3d5d..a8a1e14 100644 (file)
@@ -1989,7 +1989,7 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
        /* Sunrise Point */
        { PCI_DEVICE(0x8086, 0xa170),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
        /* Sunrise Point-LP */
        { PCI_DEVICE(0x8086, 0x9d70),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
index ce5a6da..05e19f7 100644 (file)
@@ -134,13 +134,38 @@ static void print_amp_caps(struct snd_info_buffer *buffer,
                    (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT);
 }
 
+/* is this a stereo widget or a stereo-to-mono mix? */
+static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid,
+                          int dir, unsigned int wcaps, int indices)
+{
+       hda_nid_t conn;
+
+       if (wcaps & AC_WCAP_STEREO)
+               return true;
+       /* check for a stereo-to-mono mix; it must be:
+        * only a single connection, only for input, and only a mixer widget
+        */
+       if (indices != 1 || dir != HDA_INPUT ||
+           get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
+               return false;
+
+       if (snd_hda_get_raw_connections(codec, nid, &conn, 1) < 0)
+               return false;
+       /* the connection source is a stereo? */
+       wcaps = snd_hda_param_read(codec, conn, AC_PAR_AUDIO_WIDGET_CAP);
+       return !!(wcaps & AC_WCAP_STEREO);
+}
+
 static void print_amp_vals(struct snd_info_buffer *buffer,
                           struct hda_codec *codec, hda_nid_t nid,
-                          int dir, int stereo, int indices)
+                          int dir, unsigned int wcaps, int indices)
 {
        unsigned int val;
+       bool stereo;
        int i;
 
+       stereo = is_stereo_amps(codec, nid, dir, wcaps, indices);
+
        dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
        for (i = 0; i < indices; i++) {
                snd_iprintf(buffer, " [");
@@ -757,12 +782,10 @@ static void print_codec_info(struct snd_info_entry *entry,
                            (codec->single_adc_amp &&
                             wid_type == AC_WID_AUD_IN))
                                print_amp_vals(buffer, codec, nid, HDA_INPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              1);
+                                              wid_caps, 1);
                        else
                                print_amp_vals(buffer, codec, nid, HDA_INPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              conn_len);
+                                              wid_caps, conn_len);
                }
                if (wid_caps & AC_WCAP_OUT_AMP) {
                        snd_iprintf(buffer, "  Amp-Out caps: ");
@@ -771,11 +794,10 @@ static void print_codec_info(struct snd_info_entry *entry,
                        if (wid_type == AC_WID_PIN &&
                            codec->pin_amp_workaround)
                                print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              conn_len);
+                                              wid_caps, conn_len);
                        else
                                print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
-                                              wid_caps & AC_WCAP_STEREO, 1);
+                                              wid_caps, 1);
                }
 
                switch (wid_type) {
index 526398a..7438213 100644 (file)
@@ -396,7 +396,7 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
 {
        /* We currently only handle front, HP */
        static hda_nid_t pins[] = {
-               0x0f, 0x10, 0x14, 0x15, 0
+               0x0f, 0x10, 0x14, 0x15, 0x17, 0
        };
        hda_nid_t *p;
        for (p = pins; *p; p++)
@@ -5036,6 +5036,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
index b67480f..4373ada 100644 (file)
@@ -317,7 +317,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
-       unsigned int deemph = ucontrol->value.enumerated.item[0];
+       unsigned int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
@@ -333,7 +333,7 @@ static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = adav80x->deemph;
+       ucontrol->value.integer.value[0] = adav80x->deemph;
        return 0;
 };
 
index 70861c7..81b54a2 100644 (file)
@@ -76,7 +76,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
@@ -92,7 +92,7 @@ static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = ak4641->deemph;
+       ucontrol->value.integer.value[0] = ak4641->deemph;
        return 0;
 };
 
index 632e89f..2a58b1d 100644 (file)
@@ -343,25 +343,25 @@ static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route ak4671_intercon[] = {
-       {"DAC Left", "NULL", "PMPLL"},
-       {"DAC Right", "NULL", "PMPLL"},
-       {"ADC Left", "NULL", "PMPLL"},
-       {"ADC Right", "NULL", "PMPLL"},
+       {"DAC Left", NULL, "PMPLL"},
+       {"DAC Right", NULL, "PMPLL"},
+       {"ADC Left", NULL, "PMPLL"},
+       {"ADC Right", NULL, "PMPLL"},
 
        /* Outputs */
-       {"LOUT1", "NULL", "LOUT1 Mixer"},
-       {"ROUT1", "NULL", "ROUT1 Mixer"},
-       {"LOUT2", "NULL", "LOUT2 Mix Amp"},
-       {"ROUT2", "NULL", "ROUT2 Mix Amp"},
-       {"LOUT3", "NULL", "LOUT3 Mixer"},
-       {"ROUT3", "NULL", "ROUT3 Mixer"},
+       {"LOUT1", NULL, "LOUT1 Mixer"},
+       {"ROUT1", NULL, "ROUT1 Mixer"},
+       {"LOUT2", NULL, "LOUT2 Mix Amp"},
+       {"ROUT2", NULL, "ROUT2 Mix Amp"},
+       {"LOUT3", NULL, "LOUT3 Mixer"},
+       {"ROUT3", NULL, "ROUT3 Mixer"},
 
        {"LOUT1 Mixer", "DACL", "DAC Left"},
        {"ROUT1 Mixer", "DACR", "DAC Right"},
        {"LOUT2 Mixer", "DACHL", "DAC Left"},
        {"ROUT2 Mixer", "DACHR", "DAC Right"},
-       {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"},
-       {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"},
+       {"LOUT2 Mix Amp", NULL, "LOUT2 Mixer"},
+       {"ROUT2 Mix Amp", NULL, "ROUT2 Mixer"},
        {"LOUT3 Mixer", "DACSL", "DAC Left"},
        {"ROUT3 Mixer", "DACSR", "DAC Right"},
 
@@ -381,18 +381,18 @@ static const struct snd_soc_dapm_route ak4671_intercon[] = {
        {"LIN2", NULL, "Mic Bias"},
        {"RIN2", NULL, "Mic Bias"},
 
-       {"ADC Left", "NULL", "LIN MUX"},
-       {"ADC Right", "NULL", "RIN MUX"},
+       {"ADC Left", NULL, "LIN MUX"},
+       {"ADC Right", NULL, "RIN MUX"},
 
        /* Analog Loops */
-       {"LIN1 Mixing Circuit", "NULL", "LIN1"},
-       {"RIN1 Mixing Circuit", "NULL", "RIN1"},
-       {"LIN2 Mixing Circuit", "NULL", "LIN2"},
-       {"RIN2 Mixing Circuit", "NULL", "RIN2"},
-       {"LIN3 Mixing Circuit", "NULL", "LIN3"},
-       {"RIN3 Mixing Circuit", "NULL", "RIN3"},
-       {"LIN4 Mixing Circuit", "NULL", "LIN4"},
-       {"RIN4 Mixing Circuit", "NULL", "RIN4"},
+       {"LIN1 Mixing Circuit", NULL, "LIN1"},
+       {"RIN1 Mixing Circuit", NULL, "RIN1"},
+       {"LIN2 Mixing Circuit", NULL, "LIN2"},
+       {"RIN2 Mixing Circuit", NULL, "RIN2"},
+       {"LIN3 Mixing Circuit", NULL, "LIN3"},
+       {"RIN3 Mixing Circuit", NULL, "RIN3"},
+       {"LIN4 Mixing Circuit", NULL, "LIN4"},
+       {"RIN4 Mixing Circuit", NULL, "RIN4"},
 
        {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"},
        {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"},
index 79a4efc..7d3a6ac 100644 (file)
@@ -286,7 +286,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = cs4271->deemph;
+       ucontrol->value.integer.value[0] = cs4271->deemph;
        return 0;
 }
 
@@ -296,7 +296,7 @@ static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 
-       cs4271->deemph = ucontrol->value.enumerated.item[0];
+       cs4271->deemph = ucontrol->value.integer.value[0];
        return cs4271_set_deemph(codec);
 }
 
index ffe9617..911c26c 100644 (file)
@@ -876,11 +876,11 @@ static const struct snd_soc_dapm_widget da732x_dapm_widgets[] = {
 
 static const struct snd_soc_dapm_route da732x_dapm_routes[] = {
        /* Inputs */
-       {"AUX1L PGA", "NULL", "AUX1L"},
-       {"AUX1R PGA", "NULL", "AUX1R"},
+       {"AUX1L PGA", NULL, "AUX1L"},
+       {"AUX1R PGA", NULL, "AUX1R"},
        {"MIC1 PGA", NULL, "MIC1"},
-       {"MIC2 PGA", "NULL", "MIC2"},
-       {"MIC3 PGA", "NULL", "MIC3"},
+       {"MIC2 PGA", NULL, "MIC2"},
+       {"MIC3 PGA", NULL, "MIC3"},
 
        /* Capture Path */
        {"ADC1 Left MUX", "MIC1", "MIC1 PGA"},
index f273251..c5f35a0 100644 (file)
@@ -120,7 +120,7 @@ static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = es8328->deemph;
+       ucontrol->value.integer.value[0] = es8328->deemph;
        return 0;
 }
 
@@ -129,7 +129,7 @@ static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret;
 
        if (deemph > 1)
index a722a02..477e13d 100644 (file)
@@ -118,7 +118,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = priv->deemph;
+       ucontrol->value.integer.value[0] = priv->deemph;
 
        return 0;
 }
@@ -129,7 +129,7 @@ static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       priv->deemph = ucontrol->value.enumerated.item[0];
+       priv->deemph = ucontrol->value.integer.value[0];
 
        return pcm1681_set_deemph(codec);
 }
index f374840..9b541e5 100644 (file)
@@ -1198,7 +1198,7 @@ static struct dmi_system_id dmi_dell_dino[] = {
                .ident = "Dell Dino",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_BOARD_NAME, "0144P8")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343")
                }
        },
        { }
index e182e65..3593a14 100644 (file)
@@ -1151,13 +1151,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
                /* Enable VDDC charge pump */
                ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP;
        } else if (vddio >= 3100 && vdda >= 3100) {
-               /*
-                * if vddio and vddd > 3.1v,
-                * charge pump should be clean before set ana_pwr
-                */
-               snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
-                               SGTL5000_VDDC_CHRGPMP_POWERUP, 0);
-
+               ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP;
                /* VDDC use VDDIO rail */
                lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD;
                lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO <<
index 47b257e..82095d6 100644 (file)
@@ -538,8 +538,8 @@ static const struct snd_soc_dapm_route sn95031_audio_map[] = {
        /* speaker map */
        { "IHFOUTL", NULL, "Speaker Rail"},
        { "IHFOUTR", NULL, "Speaker Rail"},
-       { "IHFOUTL", "NULL", "Speaker Left Playback"},
-       { "IHFOUTR", "NULL", "Speaker Right Playback"},
+       { "IHFOUTL", NULL, "Speaker Left Playback"},
+       { "IHFOUTR", NULL, "Speaker Right Playback"},
        { "Speaker Left Playback", NULL, "Speaker Left Filter"},
        { "Speaker Right Playback", NULL, "Speaker Right Filter"},
        { "Speaker Left Filter", NULL, "IHFDAC Left"},
index 249ef5c..32942be 100644 (file)
@@ -281,7 +281,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = priv->deemph;
+       ucontrol->value.integer.value[0] = priv->deemph;
 
        return 0;
 }
@@ -292,7 +292,7 @@ static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       priv->deemph = ucontrol->value.enumerated.item[0];
+       priv->deemph = ucontrol->value.integer.value[0];
 
        return tas5086_set_deemph(codec);
 }
index 8d9de49..21d5402 100644 (file)
@@ -610,7 +610,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       ucontrol->value.enumerated.item[0] = wm2000->anc_active;
+       ucontrol->value.integer.value[0] = wm2000->anc_active;
 
        return 0;
 }
@@ -620,7 +620,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
-       int anc_active = ucontrol->value.enumerated.item[0];
+       int anc_active = ucontrol->value.integer.value[0];
        int ret;
 
        if (anc_active > 1)
@@ -643,7 +643,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       ucontrol->value.enumerated.item[0] = wm2000->spk_ena;
+       ucontrol->value.integer.value[0] = wm2000->spk_ena;
 
        return 0;
 }
@@ -653,7 +653,7 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
-       int val = ucontrol->value.enumerated.item[0];
+       int val = ucontrol->value.integer.value[0];
        int ret;
 
        if (val > 1)
index 098c143..c6d1053 100644 (file)
@@ -125,7 +125,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8731->deemph;
+       ucontrol->value.integer.value[0] = wm8731->deemph;
 
        return 0;
 }
@@ -135,7 +135,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret = 0;
 
        if (deemph > 1)
index dde462c..04b04f8 100644 (file)
@@ -442,7 +442,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8903->deemph;
+       ucontrol->value.integer.value[0] = wm8903->deemph;
 
        return 0;
 }
@@ -452,7 +452,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret = 0;
 
        if (deemph > 1)
index d3b3f57..215e93c 100644 (file)
@@ -525,7 +525,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8904->deemph;
+       ucontrol->value.integer.value[0] = wm8904->deemph;
        return 0;
 }
 
@@ -534,7 +534,7 @@ static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index 1ab2d46..00bec91 100644 (file)
@@ -393,7 +393,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8955->deemph;
+       ucontrol->value.integer.value[0] = wm8955->deemph;
        return 0;
 }
 
@@ -402,7 +402,7 @@ static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index cf8fecf..3035d98 100644 (file)
@@ -184,7 +184,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8960->deemph;
+       ucontrol->value.integer.value[0] = wm8960->deemph;
        return 0;
 }
 
@@ -193,7 +193,7 @@ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index 9517571..98c9525 100644 (file)
@@ -180,7 +180,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val = ucontrol->value.enumerated.item[0];
+       unsigned int val = ucontrol->value.integer.value[0];
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mixer, mask, shift, old;
@@ -193,7 +193,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&wm9712->lock);
        old = wm9712->hp_mixer[mixer];
-       if (ucontrol->value.enumerated.item[0])
+       if (ucontrol->value.integer.value[0])
                wm9712->hp_mixer[mixer] |= mask;
        else
                wm9712->hp_mixer[mixer] &= ~mask;
@@ -231,7 +231,7 @@ static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
        mixer = mc->shift >> 8;
        shift = mc->shift & 0xff;
 
-       ucontrol->value.enumerated.item[0] =
+       ucontrol->value.integer.value[0] =
                (wm9712->hp_mixer[mixer] >> shift) & 1;
 
        return 0;
index 6822291..7955295 100644 (file)
@@ -255,7 +255,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val = ucontrol->value.enumerated.item[0];
+       unsigned int val = ucontrol->value.integer.value[0];
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mixer, mask, shift, old;
@@ -268,7 +268,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&wm9713->lock);
        old = wm9713->hp_mixer[mixer];
-       if (ucontrol->value.enumerated.item[0])
+       if (ucontrol->value.integer.value[0])
                wm9713->hp_mixer[mixer] |= mask;
        else
                wm9713->hp_mixer[mixer] &= ~mask;
@@ -306,7 +306,7 @@ static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol,
        mixer = mc->shift >> 8;
        shift = mc->shift & 0xff;
 
-       ucontrol->value.enumerated.item[0] =
+       ucontrol->value.integer.value[0] =
                (wm9713->hp_mixer[mixer] >> shift) & 1;
 
        return 0;
index b9fabbf..6b0c8f7 100644 (file)
@@ -603,7 +603,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
        factor = (div2 + 1) * (7 * psr + 1) * 2;
 
        for (i = 0; i < 255; i++) {
-               tmprate = freq * factor * (i + 2);
+               tmprate = freq * factor * (i + 1);
 
                if (baudclk_is_used)
                        clkrate = clk_get_rate(ssi_private->baudclk);
@@ -1227,7 +1227,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
        ssi_private->dma_params_tx.addr = ssi_private->ssi_phys + CCSR_SSI_STX0;
        ssi_private->dma_params_rx.addr = ssi_private->ssi_phys + CCSR_SSI_SRX0;
 
-       ret = !of_property_read_u32_array(np, "dmas", dmas, 4);
+       ret = of_property_read_u32_array(np, "dmas", dmas, 4);
        if (ssi_private->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) {
                ssi_private->use_dual_fifo = true;
                /* When using dual fifo mode, we need to keep watermark
index c42ffae..402b728 100644 (file)
@@ -207,9 +207,6 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
                module = (void *)module + sizeof(*module) + module->mod_size;
        }
 
-       /* allocate scratch mem regions */
-       sst_block_alloc_scratch(dsp);
-
        return 0;
 }
 
index 394af56..863a9ca 100644 (file)
@@ -1732,6 +1732,7 @@ static void sst_hsw_drop_all(struct sst_hsw *hsw)
 int sst_hsw_dsp_load(struct sst_hsw *hsw)
 {
        struct sst_dsp *dsp = hsw->dsp;
+       struct sst_fw *sst_fw, *t;
        int ret;
 
        dev_dbg(hsw->dev, "loading audio DSP....");
@@ -1748,12 +1749,17 @@ int sst_hsw_dsp_load(struct sst_hsw *hsw)
                return ret;
        }
 
-       ret = sst_fw_reload(hsw->sst_fw);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: SST FW reload failed\n");
-               sst_dsp_dma_put_channel(dsp);
-               return -ENOMEM;
+       list_for_each_entry_safe_reverse(sst_fw, t, &dsp->fw_list, list) {
+               ret = sst_fw_reload(sst_fw);
+               if (ret < 0) {
+                       dev_err(hsw->dev, "error: SST FW reload failed\n");
+                       sst_dsp_dma_put_channel(dsp);
+                       return -ENOMEM;
+               }
        }
+       ret = sst_block_alloc_scratch(hsw->dsp);
+       if (ret < 0)
+               return -EINVAL;
 
        sst_dsp_dma_put_channel(dsp);
        return 0;
@@ -1809,12 +1815,17 @@ int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw)
 
 int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw)
 {
-       sst_fw_unload(hsw->sst_fw);
-       sst_block_free_scratch(hsw->dsp);
+       struct sst_fw *sst_fw, *t;
+       struct sst_dsp *dsp = hsw->dsp;
+
+       list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) {
+               sst_fw_unload(sst_fw);
+       }
+       sst_block_free_scratch(dsp);
 
        hsw->boot_complete = false;
 
-       sst_dsp_sleep(hsw->dsp);
+       sst_dsp_sleep(dsp);
 
        return 0;
 }
@@ -1943,6 +1954,11 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
                goto fw_err;
        }
 
+       /* allocate scratch mem regions */
+       ret = sst_block_alloc_scratch(hsw->dsp);
+       if (ret < 0)
+               goto boot_err;
+
        /* wait for DSP boot completion */
        sst_dsp_boot(hsw->dsp);
        ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
index 30579ca..e5c9908 100644 (file)
@@ -347,6 +347,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(codec, &codec_list, list) {
                len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
                               codec->component.name);
@@ -358,6 +360,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        if (ret >= 0)
                ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
@@ -382,6 +386,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(component, &component_list, list) {
                list_for_each_entry(dai, &component->dai_list, list) {
                        len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
@@ -395,6 +401,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
        kfree(buf);
@@ -418,6 +426,8 @@ static ssize_t platform_list_read_file(struct file *file,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(platform, &platform_list, list) {
                len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
                               platform->component.name);
@@ -429,6 +439,8 @@ static ssize_t platform_list_read_file(struct file *file,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
        kfree(buf);
@@ -836,6 +848,8 @@ static struct snd_soc_component *soc_find_component(
 {
        struct snd_soc_component *component;
 
+       lockdep_assert_held(&client_mutex);
+
        list_for_each_entry(component, &component_list, list) {
                if (of_node) {
                        if (component->dev->of_node == of_node)
@@ -854,6 +868,8 @@ static struct snd_soc_dai *snd_soc_find_dai(
        struct snd_soc_component *component;
        struct snd_soc_dai *dai;
 
+       lockdep_assert_held(&client_mutex);
+
        /* Find CPU DAI from registered DAIs*/
        list_for_each_entry(component, &component_list, list) {
                if (dlc->of_node && component->dev->of_node != dlc->of_node)
@@ -1508,6 +1524,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        struct snd_soc_codec *codec;
        int ret, i, order;
 
+       mutex_lock(&client_mutex);
        mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 
        /* bind DAIs */
@@ -1662,6 +1679,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        card->instantiated = 1;
        snd_soc_dapm_sync(&card->dapm);
        mutex_unlock(&card->mutex);
+       mutex_unlock(&client_mutex);
 
        return 0;
 
@@ -1680,6 +1698,7 @@ card_probe_error:
 
 base_error:
        mutex_unlock(&card->mutex);
+       mutex_unlock(&client_mutex);
 
        return ret;
 }
@@ -2713,13 +2732,6 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
        list_del(&component->list);
 }
 
-static void snd_soc_component_del(struct snd_soc_component *component)
-{
-       mutex_lock(&client_mutex);
-       snd_soc_component_del_unlocked(component);
-       mutex_unlock(&client_mutex);
-}
-
 int snd_soc_register_component(struct device *dev,
                               const struct snd_soc_component_driver *cmpnt_drv,
                               struct snd_soc_dai_driver *dai_drv,
@@ -2767,14 +2779,17 @@ void snd_soc_unregister_component(struct device *dev)
 {
        struct snd_soc_component *cmpnt;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(cmpnt, &component_list, list) {
                if (dev == cmpnt->dev && cmpnt->registered_as_component)
                        goto found;
        }
+       mutex_unlock(&client_mutex);
        return;
 
 found:
-       snd_soc_component_del(cmpnt);
+       snd_soc_component_del_unlocked(cmpnt);
+       mutex_unlock(&client_mutex);
        snd_soc_component_cleanup(cmpnt);
        kfree(cmpnt);
 }
@@ -2882,10 +2897,14 @@ struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev)
 {
        struct snd_soc_platform *platform;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(platform, &platform_list, list) {
-               if (dev == platform->dev)
+               if (dev == platform->dev) {
+                       mutex_unlock(&client_mutex);
                        return platform;
+               }
        }
+       mutex_unlock(&client_mutex);
 
        return NULL;
 }
@@ -3090,15 +3109,15 @@ void snd_soc_unregister_codec(struct device *dev)
 {
        struct snd_soc_codec *codec;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(codec, &codec_list, list) {
                if (dev == codec->dev)
                        goto found;
        }
+       mutex_unlock(&client_mutex);
        return;
 
 found:
-
-       mutex_lock(&client_mutex);
        list_del(&codec->list);
        snd_soc_component_del_unlocked(&codec->component);
        mutex_unlock(&client_mutex);
index 61bf912..9d9db3b 100644 (file)
@@ -30,6 +30,8 @@ static int disasm_line__parse(char *line, char **namep, char **rawp);
 
 static void ins__delete(struct ins_operands *ops)
 {
+       if (ops == NULL)
+               return;
        zfree(&ops->source.raw);
        zfree(&ops->source.name);
        zfree(&ops->target.raw);
index 4e51122..0db5713 100644 (file)
@@ -22,6 +22,14 @@ TARGETS += vm
 TARGETS_HOTPLUG = cpu-hotplug
 TARGETS_HOTPLUG += memory-hotplug
 
+# Clear LDFLAGS and MAKEFLAGS if called from main
+# Makefile to avoid test build failures when test
+# Makefile doesn't have explicit build rules.
+ifeq (1,$(MAKELEVEL))
+undefine LDFLAGS
+override MAKEFLAGS =
+endif
+
 all:
        for TARGET in $(TARGETS); do \
                make -C $$TARGET; \
index a0a7b5d..f9b9c7c 100644 (file)
@@ -72,6 +72,8 @@ static void vgic_v2_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
 {
        if (!(lr_desc.state & LR_STATE_MASK))
                vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr |= (1ULL << lr);
+       else
+               vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr &= ~(1ULL << lr);
 }
 
 static u64 vgic_v2_get_elrsr(const struct kvm_vcpu *vcpu)
@@ -84,6 +86,11 @@ static u64 vgic_v2_get_eisr(const struct kvm_vcpu *vcpu)
        return vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr;
 }
 
+static void vgic_v2_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr = 0;
+}
+
 static u32 vgic_v2_get_interrupt_status(const struct kvm_vcpu *vcpu)
 {
        u32 misr = vcpu->arch.vgic_cpu.vgic_v2.vgic_misr;
@@ -148,6 +155,7 @@ static const struct vgic_ops vgic_v2_ops = {
        .sync_lr_elrsr          = vgic_v2_sync_lr_elrsr,
        .get_elrsr              = vgic_v2_get_elrsr,
        .get_eisr               = vgic_v2_get_eisr,
+       .clear_eisr             = vgic_v2_clear_eisr,
        .get_interrupt_status   = vgic_v2_get_interrupt_status,
        .enable_underflow       = vgic_v2_enable_underflow,
        .disable_underflow      = vgic_v2_disable_underflow,
index 3a62d8a..dff0602 100644 (file)
@@ -104,6 +104,8 @@ static void vgic_v3_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
 {
        if (!(lr_desc.state & LR_STATE_MASK))
                vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
+       else
+               vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr &= ~(1U << lr);
 }
 
 static u64 vgic_v3_get_elrsr(const struct kvm_vcpu *vcpu)
@@ -116,6 +118,11 @@ static u64 vgic_v3_get_eisr(const struct kvm_vcpu *vcpu)
        return vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr;
 }
 
+static void vgic_v3_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr = 0;
+}
+
 static u32 vgic_v3_get_interrupt_status(const struct kvm_vcpu *vcpu)
 {
        u32 misr = vcpu->arch.vgic_cpu.vgic_v3.vgic_misr;
@@ -192,6 +199,7 @@ static const struct vgic_ops vgic_v3_ops = {
        .sync_lr_elrsr          = vgic_v3_sync_lr_elrsr,
        .get_elrsr              = vgic_v3_get_elrsr,
        .get_eisr               = vgic_v3_get_eisr,
+       .clear_eisr             = vgic_v3_clear_eisr,
        .get_interrupt_status   = vgic_v3_get_interrupt_status,
        .enable_underflow       = vgic_v3_enable_underflow,
        .disable_underflow      = vgic_v3_disable_underflow,
index 0cc6ab6..c9f60f5 100644 (file)
@@ -883,6 +883,11 @@ static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
        return vgic_ops->get_eisr(vcpu);
 }
 
+static inline void vgic_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vgic_ops->clear_eisr(vcpu);
+}
+
 static inline u32 vgic_get_interrupt_status(struct kvm_vcpu *vcpu)
 {
        return vgic_ops->get_interrupt_status(vcpu);
@@ -922,6 +927,7 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
        vgic_set_lr(vcpu, lr_nr, vlr);
        clear_bit(lr_nr, vgic_cpu->lr_used);
        vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
+       vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
 }
 
 /*
@@ -978,6 +984,7 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
                        BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
                        vlr.state |= LR_STATE_PENDING;
                        vgic_set_lr(vcpu, lr, vlr);
+                       vgic_sync_lr_elrsr(vcpu, lr, vlr);
                        return true;
                }
        }
@@ -999,6 +1006,7 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
                vlr.state |= LR_EOI_INT;
 
        vgic_set_lr(vcpu, lr, vlr);
+       vgic_sync_lr_elrsr(vcpu, lr, vlr);
 
        return true;
 }
@@ -1136,6 +1144,14 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
        if (status & INT_STATUS_UNDERFLOW)
                vgic_disable_underflow(vcpu);
 
+       /*
+        * In the next iterations of the vcpu loop, if we sync the vgic state
+        * after flushing it, but before entering the guest (this happens for
+        * pending signals and vmid rollovers), then make sure we don't pick
+        * up any old maintenance interrupts here.
+        */
+       vgic_clear_eisr(vcpu);
+
        return level_pending;
 }
 
@@ -1583,8 +1599,10 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
         * emulation. So check this here again. KVM_CREATE_DEVICE does
         * the proper checks already.
         */
-       if (type == KVM_DEV_TYPE_ARM_VGIC_V2 && !vgic->can_emulate_gicv2)
-               return -ENODEV;
+       if (type == KVM_DEV_TYPE_ARM_VGIC_V2 && !vgic->can_emulate_gicv2) {
+               ret = -ENODEV;
+               goto out;
+       }
 
        /*
         * Any time a vcpu is run, vcpu_load is called which tries to grab the
index a109370..cc6a25d 100644 (file)
@@ -471,7 +471,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
        BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX);
 
        r = -ENOMEM;
-       kvm->memslots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
+       kvm->memslots = kvm_kvzalloc(sizeof(struct kvm_memslots));
        if (!kvm->memslots)
                goto out_err_no_srcu;
 
@@ -522,7 +522,7 @@ out_err_no_srcu:
 out_err_no_disable:
        for (i = 0; i < KVM_NR_BUSES; i++)
                kfree(kvm->buses[i]);
-       kfree(kvm->memslots);
+       kvfree(kvm->memslots);
        kvm_arch_free_vm(kvm);
        return ERR_PTR(r);
 }
@@ -578,7 +578,7 @@ static void kvm_free_physmem(struct kvm *kvm)
        kvm_for_each_memslot(memslot, slots)
                kvm_free_physmem_slot(kvm, memslot, NULL);
 
-       kfree(kvm->memslots);
+       kvfree(kvm->memslots);
 }
 
 static void kvm_destroy_devices(struct kvm *kvm)
@@ -871,10 +871,10 @@ int __kvm_set_memory_region(struct kvm *kvm,
                        goto out_free;
        }
 
-       slots = kmemdup(kvm->memslots, sizeof(struct kvm_memslots),
-                       GFP_KERNEL);
+       slots = kvm_kvzalloc(sizeof(struct kvm_memslots));
        if (!slots)
                goto out_free;
+       memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
 
        if ((change == KVM_MR_DELETE) || (change == KVM_MR_MOVE)) {
                slot = id_to_memslot(slots, mem->slot);
@@ -917,7 +917,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        kvm_arch_commit_memory_region(kvm, mem, &old, change);
 
        kvm_free_physmem_slot(kvm, &old, &new);
-       kfree(old_memslots);
+       kvfree(old_memslots);
 
        /*
         * IOMMU mapping:  New slots need to be mapped.  Old slots need to be
@@ -936,7 +936,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        return 0;
 
 out_slots:
-       kfree(slots);
+       kvfree(slots);
 out_free:
        kvm_free_physmem_slot(kvm, &new, &old);
 out:
@@ -2492,6 +2492,7 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
        case KVM_CAP_SIGNAL_MSI:
 #endif
 #ifdef CONFIG_HAVE_KVM_IRQFD
+       case KVM_CAP_IRQFD:
        case KVM_CAP_IRQFD_RESAMPLE:
 #endif
        case KVM_CAP_CHECK_EXTENSION_VM: