]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge branch 'vmwgfx-next' of git://people.freedesktop.org/~thomash/linux into drm...
authorDave Airlie <airlied@redhat.com>
Mon, 17 Aug 2015 06:03:48 +0000 (16:03 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 17 Aug 2015 06:03:48 +0000 (16:03 +1000)
A couple of fixes from the previous pull request as well as gl3 support.
There is one drm core change, an export of a previously private function.

Take 2 implementing screen targets, this time with the fbdev code adjusted
accordingly.

Also there is an implementation of register-driven command buffers, that
overrides the FIFO ring for command processing. It's needed for our upcoming
hardware revision.
* 'vmwgfx-next' of git://people.freedesktop.org/~thomash/linux: (35 commits)
  drm/vmwgfx: Fix copyright headers
  drm/vmwgfx: Add DX query support. Various fixes.
  drm/vmwgfx: Add command parser support for a couple of DX commands
  drm/vmwgfx: Command parser fixes for DX
  drm/vmwgfx: Initial DX support
  drm/vmwgfx: Update device includes for DX device functionality
  drm: export the DRM permission check code
  drm/vmwgfx: Fix crash when unloading vmwgfx v2
  drm/vmwgfx: Fix framebuffer creation on older hardware
  drm/vmwgfx: Fixed topology boundary checking for Screen Targets
  drm/vmwgfx: Fix an uninitialized value
  drm/vmwgfx: Fix compiler warning with 32-bit dma_addr_t
  drm/vmwgfx: Kill a bunch of sparse warnings
  drm/vmwgfx: Fix kms preferred mode sorting
  drm/vmwgfx: Reinstate the legacy display system dirty callback
  drm/vmwgfx: Implement fbdev on kms v2
  drm/vmwgfx: Add a kernel interface to create a framebuffer v2
  drm/vmwgfx: Avoid cmdbuf alloc sleeping if !TASK_RUNNING
  drm/vmwgfx: Convert screen targets to new helpers v3
  drm/vmwgfx: Convert screen objects to the new helpers
  ...

1072 files changed:
.mailmap
Documentation/DocBook/drm.tmpl
Documentation/devicetree/bindings/arm/cpus.txt
Documentation/devicetree/bindings/dma/apm-xgene-dma.txt
Documentation/devicetree/bindings/drm/msm/dsi.txt
Documentation/devicetree/bindings/drm/msm/hdmi.txt
Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
Documentation/devicetree/bindings/gpu/st,stih4xx.txt
Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
Documentation/devicetree/bindings/panel/auo,b080uan01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/lg,lg4573.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/nec,nl4827hc19-05b.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/okaya,rs800480t-7x0gp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/ti-phy.txt
Documentation/devicetree/bindings/sound/mt8173-max98090.txt
Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt
Documentation/devicetree/bindings/spi/spi-ath79.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/hwmon/nct7904
Documentation/input/alps.txt
Documentation/target/tcm_mod_builder.py
MAINTAINERS
Makefile
arch/arc/Kconfig
arch/arc/Makefile
arch/arc/include/asm/arcregs.h
arch/arc/include/asm/atomic.h
arch/arc/include/asm/ptrace.h
arch/arc/include/asm/spinlock.h
arch/arc/include/asm/spinlock_types.h
arch/arc/include/uapi/asm/ptrace.h
arch/arc/kernel/setup.c
arch/arc/kernel/time.c
arch/arc/lib/memcpy-archs.S
arch/arc/lib/memset-archs.S
arch/arc/plat-axs10x/axs10x.c
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/exynos3250.dtsi
arch/arm/boot/dts/exynos4210-origen.dts
arch/arm/boot/dts/exynos4210-trats.dts
arch/arm/boot/dts/exynos4210-universal_c210.dts
arch/arm/boot/dts/exynos4210.dtsi
arch/arm/boot/dts/imx25-pdk.dts
arch/arm/boot/dts/imx35.dtsi
arch/arm/boot/dts/imx51-apf51dev.dts
arch/arm/boot/dts/imx53-ard.dts
arch/arm/boot/dts/imx53-m53evk.dts
arch/arm/boot/dts/imx53-qsb-common.dtsi
arch/arm/boot/dts/imx53-smd.dts
arch/arm/boot/dts/imx53-tqma53.dtsi
arch/arm/boot/dts/imx53-tx53.dtsi
arch/arm/boot/dts/imx53-voipac-bsb.dts
arch/arm/boot/dts/imx6dl-riotboard.dts
arch/arm/boot/dts/imx6q-arm2.dts
arch/arm/boot/dts/imx6q-gk802.dts
arch/arm/boot/dts/imx6q-tbs2910.dts
arch/arm/boot/dts/imx6qdl-aristainetos.dtsi
arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi
arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi
arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
arch/arm/boot/dts/imx6qdl-rex.dtsi
arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
arch/arm/boot/dts/imx6qdl-sabresd.dtsi
arch/arm/boot/dts/imx6qdl-tx6.dtsi
arch/arm/boot/dts/imx6qdl-wandboard.dtsi
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/imx6sl-evk.dts
arch/arm/boot/dts/imx6sx-sabreauto.dts
arch/arm/boot/dts/imx6sx-sdb.dtsi
arch/arm/boot/dts/imx7d-sdb.dts
arch/arm/boot/dts/k2e-clocks.dtsi
arch/arm/boot/dts/k2e.dtsi
arch/arm/boot/dts/k2hk-clocks.dtsi
arch/arm/boot/dts/k2hk.dtsi
arch/arm/boot/dts/k2l-clocks.dtsi
arch/arm/boot/dts/k2l.dtsi
arch/arm/boot/dts/keystone.dtsi
arch/arm/boot/dts/omap2430.dtsi
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/ste-dbx5x0.dtsi
arch/arm/boot/dts/ste-nomadik-nhk15.dts
arch/arm/boot/dts/ste-nomadik-s8815.dts
arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
arch/arm/configs/exynos_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/kernel/entry-common.S
arch/arm/kernel/head.S
arch/arm/kernel/vdso.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/net/bpf_jit_32.c
arch/arm/vdso/Makefile
arch/arm64/boot/dts/apm/apm-storm.dtsi
arch/arm64/kernel/efi.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/irq.c
arch/arm64/kernel/signal32.c
arch/arm64/kernel/vdso.c
arch/avr32/kernel/time.c
arch/avr32/mach-at32ap/clock.c
arch/m32r/include/asm/io.h
arch/mips/Kconfig
arch/mips/ath79/setup.c
arch/mips/cavium-octeon/smp.c
arch/mips/include/asm/mach-bcm63xx/dma-coherence.h [deleted file]
arch/mips/include/asm/pgtable.h
arch/mips/include/asm/smp.h
arch/mips/include/asm/stackframe.h
arch/mips/kernel/mips-mt-fpaff.c
arch/mips/kernel/prom.c
arch/mips/kernel/relocate_kernel.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/signal32.c
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/smp.c
arch/mips/kernel/traps.c
arch/mips/kernel/unaligned.c
arch/mips/lantiq/irq.c
arch/mips/loongson64/loongson-3/smp.c
arch/mips/mm/cache.c
arch/mips/mm/fault.c
arch/mips/mti-malta/malta-int.c
arch/mips/mti-malta/malta-time.c
arch/mips/mti-sead3/sead3-time.c
arch/mips/netlogic/common/smp.c
arch/mips/paravirt/paravirt-smp.c
arch/mips/pistachio/time.c
arch/mips/pmcs-msp71xx/msp_smp.c
arch/mips/ralink/irq.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sibyte/bcm1480/smp.c
arch/mips/sibyte/sb1250/smp.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/cache.c
arch/s390/kernel/entry.S
arch/s390/kernel/traps.c
arch/s390/kvm/kvm-s390.c
arch/s390/net/bpf_jit_comp.c
arch/sparc/include/asm/visasm.h
arch/sparc/lib/NG4memcpy.S
arch/sparc/lib/VISsave.S
arch/sparc/lib/ksyms.c
arch/tile/kernel/compat_signal.c
arch/tile/kernel/setup.c
arch/x86/boot/compressed/eboot.c
arch/x86/entry/entry_64_compat.S
arch/x86/include/asm/desc.h
arch/x86/include/asm/mmu.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/sigcontext.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/include/uapi/asm/sigcontext.h
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_cqm.c
arch/x86/kernel/fpu/init.c
arch/x86/kernel/ldt.c
arch/x86/kernel/process_64.c
arch/x86/kernel/signal.c
arch/x86/kernel/step.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mtrr.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/math-emu/fpu_entry.c
arch/x86/math-emu/fpu_system.h
arch/x86/math-emu/get_address.c
arch/x86/mm/ioremap.c
arch/x86/mm/mmap.c
arch/x86/mm/mpx.c
arch/x86/mm/tlb.c
arch/x86/net/bpf_jit_comp.c
arch/x86/platform/efi/efi.c
arch/x86/power/cpu.c
arch/x86/xen/Makefile
arch/x86/xen/enlighten.c
arch/x86/xen/xen-ops.h
block/bio.c
block/blk-cgroup.c
block/blk-settings.c
drivers/acpi/device_pm.c
drivers/ata/libata-core.c
drivers/ata/libata-pmp.c
drivers/ata/libata-scsi.c
drivers/ata/libata-transport.c
drivers/base/regmap/regcache-rbtree.c
drivers/block/null_blk.c
drivers/block/rbd.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkfront.c
drivers/block/zram/zram_drv.c
drivers/bluetooth/btbcm.c
drivers/char/hw_random/core.c
drivers/clk/pxa/clk-pxa3xx.c
drivers/clocksource/sh_cmt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/loongson2_cpufreq.c
drivers/crypto/ixp4xx_crypto.c
drivers/crypto/qat/qat_common/qat_algs.c
drivers/dma/at_hdmac.c
drivers/dma/at_hdmac_regs.h
drivers/dma/at_xdmac.c
drivers/dma/mv_xor.c
drivers/dma/pl330.c
drivers/dma/virt-dma.c
drivers/dma/virt-dma.h
drivers/dma/xgene-dma.c
drivers/edac/ppc4xx_edac.c
drivers/extcon/extcon-palmas.c
drivers/extcon/extcon.c
drivers/firmware/efi/cper.c
drivers/firmware/efi/efi.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
drivers/gpu/drm/amd/amdgpu/cik_sdma.c
drivers/gpu/drm/amd/amdgpu/cz_dpm.c
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c
drivers/gpu/drm/armada/armada_fbdev.c
drivers/gpu/drm/ast/ast_fb.c
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/bochs/bochs_drv.c
drivers/gpu/drm/bochs/bochs_fbdev.c
drivers/gpu/drm/bochs/bochs_mm.c
drivers/gpu/drm/bridge/Kconfig
drivers/gpu/drm/bridge/Makefile
drivers/gpu/drm/bridge/nxp-ptn3460.c [moved from drivers/gpu/drm/bridge/ptn3460.c with 100% similarity]
drivers/gpu/drm/bridge/parade-ps8622.c [moved from drivers/gpu/drm/bridge/ps8622.c with 100% similarity]
drivers/gpu/drm/cirrus/cirrus_drv.c
drivers/gpu/drm/cirrus/cirrus_fbdev.c
drivers/gpu/drm/cirrus/cirrus_main.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_gem_cma_helper.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_modeset_lock.c
drivers/gpu/drm/drm_plane_helper.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/Makefile
drivers/gpu/drm/exynos/exynos5433_drm_decon.c
drivers/gpu/drm/exynos/exynos7_drm_decon.c
drivers/gpu/drm/exynos/exynos_dp_core.c
drivers/gpu/drm/exynos/exynos_dp_core.h
drivers/gpu/drm/exynos/exynos_drm_buf.c [deleted file]
drivers/gpu/drm/exynos/exynos_drm_buf.h [deleted file]
drivers/gpu/drm/exynos/exynos_drm_core.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_crtc.h
drivers/gpu/drm/exynos/exynos_drm_dmabuf.c [deleted file]
drivers/gpu/drm/exynos/exynos_drm_dmabuf.h [deleted file]
drivers/gpu/drm/exynos/exynos_drm_dpi.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_encoder.c [deleted file]
drivers/gpu/drm/exynos/exynos_drm_encoder.h [deleted file]
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_fb.h
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/gpu/drm/exynos/exynos_drm_gem.h
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_drm_iommu.c
drivers/gpu/drm/exynos/exynos_drm_iommu.h
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/gma500/accel_2d.c
drivers/gpu/drm/gma500/framebuffer.c
drivers/gpu/drm/i2c/tda998x_drv.c
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_cmd_parser.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_fence.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_render_state.c
drivers/gpu/drm/i915/i915_gem_render_state.h
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_guc_reg.h [new file with mode: 0644]
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/intel_bios.c
drivers/gpu/drm/i915/intel_bios.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_csr.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_guc_fwif.h [new file with mode: 0644]
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_hotplug.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_psr.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/mgag200/mgag200_cursor.c
drivers/gpu/drm/mgag200/mgag200_fb.c
drivers/gpu/drm/mgag200/mgag200_main.c
drivers/gpu/drm/msm/Kconfig
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/adreno/a2xx.xml.h
drivers/gpu/drm/msm/adreno/a3xx.xml.h
drivers/gpu/drm/msm/adreno/a4xx.xml.h
drivers/gpu/drm/msm/adreno/adreno_common.xml.h
drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
drivers/gpu/drm/msm/dsi/dsi.c
drivers/gpu/drm/msm/dsi/dsi.h
drivers/gpu/drm/msm/dsi/dsi.xml.h
drivers/gpu/drm/msm/dsi/dsi_cfg.c [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/dsi_cfg.h [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/dsi_host.c
drivers/gpu/drm/msm/dsi/dsi_manager.c
drivers/gpu/drm/msm/dsi/mmss_cc.xml.h
drivers/gpu/drm/msm/dsi/phy/dsi_phy.c [moved from drivers/gpu/drm/msm/dsi/dsi_phy.c with 54% similarity]
drivers/gpu/drm/msm/dsi/phy/dsi_phy.h [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c
drivers/gpu/drm/msm/dsi/sfpb.xml.h
drivers/gpu/drm/msm/edp/edp.xml.h
drivers/gpu/drm/msm/edp/edp_ctrl.c
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi.h
drivers/gpu/drm/msm/hdmi/hdmi.xml.h
drivers/gpu/drm/msm/hdmi/hdmi_audio.c
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
drivers/gpu/drm/msm/hdmi/hdmi_connector.c
drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c [new file with mode: 0644]
drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c
drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c
drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c
drivers/gpu/drm/msm/hdmi/qfprom.xml.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.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
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/mdp/mdp5/mdp5_smp.h
drivers/gpu/drm/msm/mdp/mdp_common.xml.h
drivers/gpu/drm/msm/mdp/mdp_format.c
drivers/gpu/drm/msm/mdp/mdp_kms.c
drivers/gpu/drm/msm/mdp/mdp_kms.h
drivers/gpu/drm/msm/msm_atomic.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_prime.c
drivers/gpu/drm/nouveau/dispnv04/overlay.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_platform.c
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/nouveau/nv04_fbcon.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_fbcon.c
drivers/gpu/drm/nouveau/nvc0_fbcon.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c
drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c
drivers/gpu/drm/omapdrm/omap_crtc.c
drivers/gpu/drm/omapdrm/omap_fbdev.c
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/Makefile
drivers/gpu/drm/panel/panel-lg-lg4573.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-samsung-ld9040.c [moved from drivers/gpu/drm/panel/panel-ld9040.c with 99% similarity]
drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c [moved from drivers/gpu/drm/panel/panel-s6e8aa0.c with 99% similarity]
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/qxl/qxl_fb.c
drivers/gpu/drm/qxl/qxl_object.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/dce6_afmt.c
drivers/gpu/drm/radeon/radeon_audio.c
drivers/gpu/drm/radeon/radeon_audio.h
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_dp_mst.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/sti/Makefile
drivers/gpu/drm/sti/sti_compositor.c
drivers/gpu/drm/sti/sti_compositor.h
drivers/gpu/drm/sti/sti_crtc.c [moved from drivers/gpu/drm/sti/sti_drm_crtc.c with 56% similarity]
drivers/gpu/drm/sti/sti_crtc.h [new file with mode: 0644]
drivers/gpu/drm/sti/sti_cursor.c
drivers/gpu/drm/sti/sti_cursor.h
drivers/gpu/drm/sti/sti_drm_crtc.h [deleted file]
drivers/gpu/drm/sti/sti_drm_plane.c [deleted file]
drivers/gpu/drm/sti/sti_drm_plane.h [deleted file]
drivers/gpu/drm/sti/sti_drv.c [moved from drivers/gpu/drm/sti/sti_drm_drv.c with 61% similarity]
drivers/gpu/drm/sti/sti_drv.h [moved from drivers/gpu/drm/sti/sti_drm_drv.h with 90% similarity]
drivers/gpu/drm/sti/sti_gdp.c
drivers/gpu/drm/sti/sti_gdp.h
drivers/gpu/drm/sti/sti_hdmi.c
drivers/gpu/drm/sti/sti_hqvdp.c
drivers/gpu/drm/sti/sti_hqvdp.h [deleted file]
drivers/gpu/drm/sti/sti_layer.c [deleted file]
drivers/gpu/drm/sti/sti_layer.h [deleted file]
drivers/gpu/drm/sti/sti_mixer.c
drivers/gpu/drm/sti/sti_mixer.h
drivers/gpu/drm/sti/sti_plane.c [new file with mode: 0644]
drivers/gpu/drm/sti/sti_plane.h [new file with mode: 0644]
drivers/gpu/drm/sti/sti_tvout.c
drivers/gpu/drm/sti/sti_vid.c
drivers/gpu/drm/sti/sti_vid.h
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/dc.h
drivers/gpu/drm/tegra/dpaux.c
drivers/gpu/drm/tegra/dpaux.h
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/dsi.c
drivers/gpu/drm/tegra/dsi.h
drivers/gpu/drm/tegra/fb.c
drivers/gpu/drm/tegra/hdmi.c
drivers/gpu/drm/tegra/output.c
drivers/gpu/drm/tegra/rgb.c
drivers/gpu/drm/tegra/sor.c
drivers/gpu/drm/tegra/sor.h
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/udl/udl_fb.c
drivers/gpu/drm/virtio/virtgpu_fb.c
drivers/gpu/drm/vmwgfx/vmwgfx_context.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
drivers/gpu/host1x/mipi.c
drivers/gpu/vga/vga_switcheroo.c
drivers/gpu/vga/vgaarb.c
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-cp2112.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-uclogic.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
drivers/hwmon/dell-smm-hwmon.c
drivers/hwmon/g762.c
drivers/hwmon/nct7802.c
drivers/hwmon/nct7904.c
drivers/i2c/busses/i2c-bfin-twi.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-slave-eeprom.c
drivers/iio/accel/mma8452.c
drivers/iio/adc/mcp320x.c
drivers/iio/adc/vf610_adc.c
drivers/iio/light/stk3310.c
drivers/iio/magnetometer/Kconfig
drivers/iio/magnetometer/bmc150_magn.c
drivers/iio/magnetometer/mmc35240.c
drivers/iio/temperature/mlx90614.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/ocrdma/ocrdma.h
drivers/infiniband/hw/ocrdma/ocrdma_abi.h
drivers/infiniband/hw/ocrdma/ocrdma_ah.c
drivers/infiniband/hw/ocrdma/ocrdma_ah.h
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
drivers/infiniband/hw/ocrdma/ocrdma_hw.h
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/ocrdma/ocrdma_sli.h
drivers/infiniband/hw/ocrdma/ocrdma_stats.c
drivers/infiniband/hw/ocrdma/ocrdma_stats.h
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
drivers/infiniband/ulp/ipoib/ipoib_verbs.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/input/input-leds.c
drivers/input/joystick/turbografx.c
drivers/input/misc/axp20x-pek.c
drivers/input/misc/twl4030-vibra.c
drivers/input/mouse/alps.c
drivers/input/mouse/bcm5974.c
drivers/input/mouse/elantech.c
drivers/input/mouse/elantech.h
drivers/input/mouse/synaptics.c
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_v2.c
drivers/iommu/arm-smmu-v3.c
drivers/iommu/intel-iommu.c
drivers/irqchip/irq-mips-gic.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/macintosh/ans-lcd.c
drivers/md/Kconfig
drivers/md/bitmap.c
drivers/md/dm-cache-policy-mq.c
drivers/md/dm-cache-policy-smq.c
drivers/md/dm-cache-target.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/md/md-cluster.c
drivers/md/md-cluster.h
drivers/md/md.c
drivers/md/persistent-data/dm-btree-internal.h
drivers/md/persistent-data/dm-btree-remove.c
drivers/md/persistent-data/dm-btree-spine.c
drivers/md/persistent-data/dm-btree.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/pci/ivtv/ivtvfb.c
drivers/memory/omap-gpmc.c
drivers/mfd/Kconfig
drivers/mfd/arizona-core.c
drivers/misc/eeprom/at24.c
drivers/misc/mei/main.c
drivers/misc/mic/scif/scif_nodeqp.c
drivers/mmc/card/block.c
drivers/mmc/host/Kconfig
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-esdhc.h
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci.c
drivers/net/bonding/bond_main.c
drivers/net/can/at91_can.c
drivers/net/can/bfin_can.c
drivers/net/can/cc770/cc770.c
drivers/net/can/flexcan.c
drivers/net/can/grcan.c
drivers/net/can/sja1000/sja1000.c
drivers/net/can/slcan.c
drivers/net/can/spi/mcp251x.c
drivers/net/can/ti_hecc.c
drivers/net/can/usb/ems_usb.c
drivers/net/can/usb/esd_usb2.c
drivers/net/can/usb/peak_usb/pcan_usb.c
drivers/net/can/usb/peak_usb/pcan_usb_pro.c
drivers/net/can/usb/usb_8dev.c
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/mv88e6xxx.c
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/cavium/Kconfig
drivers/net/ethernet/cavium/thunder/nic.h
drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.h
drivers/net/ethernet/cavium/thunder/thunder_bgx.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_ptp.c
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
drivers/net/ethernet/freescale/fs_enet/mac-fec.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/freescale/gianfar_ethtool.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/mvpp2.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/rocker/rocker.c
drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/netcp.h
drivers/net/ethernet/ti/netcp_core.c
drivers/net/ethernet/ti/netcp_ethss.c
drivers/net/ethernet/ti/netcp_sgmii.c
drivers/net/hamradio/mkiss.c
drivers/net/ipvlan/ipvlan.h
drivers/net/ipvlan/ipvlan_core.c
drivers/net/ipvlan/ipvlan_main.c
drivers/net/macvtap.c
drivers/net/ntb_netdev.c
drivers/net/phy/dp83867.c
drivers/net/phy/mdio_bus.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/virtio_net.c
drivers/net/wan/cosa.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sta.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/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
drivers/net/wireless/rsi/rsi_91x_usb_ops.c
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/rtl8723be/sw.c
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/ntb/ntb.c
drivers/ntb/ntb_transport.c
drivers/nvdimm/region_devs.c
drivers/of/Kconfig
drivers/of/unittest.c
drivers/parport/share.c
drivers/phy/Kconfig
drivers/phy/phy-berlin-usb.c
drivers/phy/phy-sun4i-usb.c
drivers/phy/phy-ti-pipe3.c
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/freescale/pinctrl-imx1-core.c
drivers/pinctrl/nomadik/pinctrl-abx500.c
drivers/pinctrl/pinctrl-lpc18xx.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/sh-pfc/sh_pfc.h
drivers/platform/chrome/Kconfig
drivers/regulator/88pm800.c
drivers/regulator/core.c
drivers/regulator/max8973-regulator.c
drivers/regulator/s2mps11.c
drivers/s390/Makefile
drivers/s390/virtio/Makefile [moved from drivers/s390/kvm/Makefile with 100% similarity]
drivers/s390/virtio/kvm_virtio.c [moved from drivers/s390/kvm/kvm_virtio.c with 100% similarity]
drivers/s390/virtio/virtio_ccw.c [moved from drivers/s390/kvm/virtio_ccw.c with 100% similarity]
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libiscsi.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/sd.c
drivers/scsi/virtio_scsi.c
drivers/spi/Kconfig
drivers/spi/spi-img-spfi.c
drivers/spi/spi-imx.c
drivers/spi/spi-zynqmp-gqspi.c
drivers/spi/spidev.c
drivers/staging/comedi/drivers/das1800.c
drivers/staging/lustre/lustre/obdclass/debug.c
drivers/staging/vt6655/device_main.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_login.h
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/target_core_configfs.c
drivers/target/target_core_pr.c
drivers/target/target_core_rd.c
drivers/target/target_core_spc.c
drivers/thermal/hisi_thermal.c
drivers/thermal/power_allocator.c
drivers/thermal/samsung/Kconfig
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/thermal_core.c
drivers/tty/n_tty.c
drivers/tty/serial/Kconfig
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/etraxfs-uart.c
drivers/tty/serial/imx.c
drivers/tty/serial/sc16is7xx.c
drivers/tty/serial/serial_core.c
drivers/tty/vt/selection.c
drivers/tty/vt/vt.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/host.c
drivers/usb/chipidea/host.h
drivers/usb/class/cdc-acm.c
drivers/usb/common/ulpi.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/usb.h
drivers/usb/dwc3/ep0.c
drivers/usb/gadget/function/f_hid.c
drivers/usb/gadget/function/f_printer.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/udc/bdc/bdc_ep.c
drivers/usb/gadget/udc/mv_udc_core.c
drivers/usb/gadget/udc/udc-core.c
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci-tmio.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.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/serial/option.c
drivers/usb/serial/qcserial.c
drivers/usb/serial/sierra.c
drivers/usb/storage/unusual_devs.h
drivers/vfio/vfio.c
drivers/vhost/vhost.c
drivers/video/Kconfig
drivers/video/console/fbcon.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/omap2/dss/dss-of.c
drivers/video/fbdev/pxa3xx-gcu.c
drivers/video/of_videomode.c
drivers/virtio/virtio_input.c
drivers/xen/balloon.c
drivers/xen/gntdev.c
drivers/xen/xenbus/xenbus_client.c
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/qgroup.c
fs/btrfs/transaction.c
fs/ceph/caps.c
fs/ceph/locks.c
fs/ceph/super.h
fs/dax.c
fs/dcache.c
fs/f2fs/data.c
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/inline.c
fs/f2fs/segment.c
fs/file_table.c
fs/fs-writeback.c
fs/fuse/dev.c
fs/hugetlbfs/inode.c
fs/namei.c
fs/namespace.c
fs/nfs/client.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs42proc.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/write.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/notify/mark.c
fs/ocfs2/aops.c
fs/ocfs2/dlmglue.c
fs/pnode.h
fs/signalfd.c
fs/udf/inode.c
fs/xfs/libxfs/xfs_attr_remote.c
fs/xfs/xfs_file.c
fs/xfs/xfs_log_recover.c
include/drm/drmP.h
include/drm/drm_atomic.h
include/drm/drm_atomic_helper.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_dp_helper.h
include/drm/drm_fb_helper.h
include/drm/drm_modeset_lock.h
include/drm/drm_pciids.h
include/drm/drm_plane_helper.h
include/linux/ata.h
include/linux/cper.h
include/linux/cpufreq.h
include/linux/fs.h
include/linux/ftrace.h
include/linux/libata.h
include/linux/mtd/nand.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/of_device.h
include/linux/page-flags.h
include/linux/platform_data/macb.h
include/linux/platform_data/mmc-esdhc-imx.h
include/linux/skbuff.h
include/net/act_api.h
include/net/cfg80211.h
include/net/inet_frag.h
include/net/ip.h
include/net/ip_fib.h
include/net/netfilter/nf_conntrack.h
include/net/netns/conntrack.h
include/net/sock.h
include/target/iscsi/iscsi_target_core.h
include/uapi/drm/amdgpu_drm.h
include/uapi/drm/i915_drm.h
include/uapi/drm/radeon_drm.h
include/uapi/linux/pci_regs.h
include/uapi/linux/virtio_net.h
include/uapi/linux/virtio_pci.h
include/uapi/linux/virtio_ring.h
include/uapi/sound/asoc.h
init/main.c
ipc/mqueue.c
ipc/sem.c
ipc/shm.c
kernel/events/core.c
kernel/events/ring_buffer.c
kernel/kthread.c
kernel/locking/qspinlock_paravirt.h
kernel/module.c
kernel/resource.c
kernel/signal.c
kernel/trace/ftrace.c
lib/iommu-common.c
mm/cma.h
mm/huge_memory.c
mm/kasan/kasan.c
mm/kasan/report.c
mm/memory-failure.c
mm/memory_hotplug.c
mm/migrate.c
mm/page-writeback.c
mm/page_alloc.c
mm/shmem.c
mm/slab_common.c
mm/vmscan.c
net/9p/trans_virtio.c
net/ax25/ax25_subr.c
net/batman-adv/distributed-arp-table.c
net/batman-adv/gateway_client.c
net/batman-adv/soft-interface.c
net/batman-adv/translation-table.c
net/bluetooth/mgmt.c
net/bluetooth/smp.c
net/bridge/br_forward.c
net/bridge/br_mdb.c
net/bridge/br_multicast.c
net/bridge/br_netlink.c
net/bridge/br_stp.c
net/bridge/br_stp_if.c
net/bridge/br_stp_timer.c
net/caif/caif_socket.c
net/core/datagram.c
net/core/dst.c
net/core/netclassid_cgroup.c
net/core/pktgen.c
net/core/request_sock.c
net/core/rtnetlink.c
net/core/sock.c
net/dccp/proto.c
net/dsa/slave.c
net/ieee802154/6lowpan/reassembly.c
net/ipv4/arp.c
net/ipv4/datagram.c
net/ipv4/devinet.c
net/ipv4/fib_lookup.h
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_fragment.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_fragment.c
net/ipv4/netfilter/ipt_SYNPROXY.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/datagram.c
net/ipv6/ip6_offload.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6t_SYNPROXY.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/llc/af_llc.c
net/mac80211/debugfs_netdev.c
net/mac80211/iface.c
net/mac80211/mesh_plink.c
net/mac80211/pm.c
net/mac80211/tdls.c
net/mac80211/tx.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_sched.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_synproxy_core.c
net/netfilter/xt_CT.c
net/netfilter/xt_IDLETIMER.c
net/netlink/af_netlink.c
net/openvswitch/actions.c
net/openvswitch/flow_table.c
net/packet/af_packet.c
net/rds/info.c
net/sched/act_api.c
net/sched/act_bpf.c
net/sched/act_mirred.c
net/sched/act_pedit.c
net/sched/cls_bpf.c
net/sched/cls_flow.c
net/sched/cls_flower.c
net/sched/sch_choke.c
net/sched/sch_fq_codel.c
net/sched/sch_plug.c
net/sched/sch_sfq.c
net/sctp/socket.c
net/sunrpc/backchannel_rqst.c
net/sunrpc/clnt.c
net/sunrpc/xprtsock.c
net/wireless/chan.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/trace.h
samples/trace_events/trace-events-sample.h
scripts/kconfig/streamline_config.pl
security/keys/keyring.c
security/yama/yama_lsm.c
sound/core/pcm_native.c
sound/firewire/amdtp.c
sound/firewire/amdtp.h
sound/firewire/fireworks/fireworks.c
sound/firewire/fireworks/fireworks.h
sound/firewire/fireworks/fireworks_stream.c
sound/hda/ext/hdac_ext_controller.c
sound/hda/ext/hdac_ext_stream.c
sound/hda/hdac_i915.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/oxygen/oxygen_mixer.c
sound/soc/codecs/cs4265.c
sound/soc/codecs/pcm1681.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/sgtl5000.h
sound/soc/codecs/ssm4567.c
sound/soc/fsl/fsl_ssi.c
sound/soc/intel/Makefile
sound/soc/intel/atom/sst/sst_drv_interface.c
sound/soc/intel/baytrail/sst-baytrail-ipc.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/haswell/sst-haswell-ipc.c
sound/soc/mediatek/mt8173-max98090.c
sound/soc/mediatek/mt8173-rt5650-rt5676.c
sound/soc/mediatek/mtk-afe-pcm.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-topology.c
sound/soc/zte/zx296702-i2s.c
sound/soc/zte/zx296702-spdif.c
sound/sparc/amd7930.c
sound/usb/mixer_maps.c
tools/perf/config/Makefile
tools/perf/util/stat-shadow.c
tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c

index b4091b7a78fe11ccd0e5f44f0703ace69dc09707..4b31af54ccd5864359c0810f9733f3026181a631 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -17,6 +17,7 @@ Aleksey Gorelov <aleksey_gorelov@phoenix.com>
 Al Viro <viro@ftp.linux.org.uk>
 Al Viro <viro@zenIV.linux.org.uk>
 Andreas Herrmann <aherrman@de.ibm.com>
+Andrey Ryabinin <ryabinin.a.a@gmail.com> <a.ryabinin@samsung.com>
 Andrew Morton <akpm@linux-foundation.org>
 Andrew Vasquez <andrew.vasquez@qlogic.com>
 Andy Adamson <andros@citi.umich.edu>
index 30b3651d642b5cb68f9b2e32748d3c05d2c7e5ac..9ddf8c6cb88791e1f0f5a12629cd9ce5be30f2e7 100644 (file)
@@ -3982,7 +3982,6 @@ int num_ioctls;</synopsis>
         <title>Interrupt Handling</title>
 !Pdrivers/gpu/drm/i915/i915_irq.c interrupt handling
 !Fdrivers/gpu/drm/i915/i915_irq.c intel_irq_init intel_irq_init_hw intel_hpd_init
-!Fdrivers/gpu/drm/i915/i915_irq.c intel_irq_fini
 !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_disable_interrupts
 !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_enable_interrupts
       </sect2>
@@ -4197,6 +4196,23 @@ int num_ioctls;</synopsis>
         <title>Global GTT views</title>
 !Pdrivers/gpu/drm/i915/i915_gem_gtt.c Global GTT views
 !Idrivers/gpu/drm/i915/i915_gem_gtt.c
+      </sect2>
+      <sect2>
+        <title>GTT Fences and Swizzling</title>
+!Idrivers/gpu/drm/i915/i915_gem_fence.c
+        <sect3>
+          <title>Global GTT Fence Handling</title>
+!Pdrivers/gpu/drm/i915/i915_gem_fence.c fence register handling
+        </sect3>
+        <sect3>
+          <title>Hardware Tiling and Swizzling Details</title>
+!Pdrivers/gpu/drm/i915/i915_gem_fence.c tiling swizzling details
+        </sect3>
+      </sect2>
+      <sect2>
+        <title>Object Tiling IOCTLs</title>
+!Idrivers/gpu/drm/i915/i915_gem_tiling.c
+!Pdrivers/gpu/drm/i915/i915_gem_tiling.c buffer object tiling
       </sect2>
       <sect2>
         <title>Buffer Object Eviction</title>
index d6b794cef0b8b9907ab5a055a6502180b4350148..91e6e5c478d006245c5a88e7ae7e304d6fa7f097 100644 (file)
@@ -199,6 +199,7 @@ nodes to be present and contain the properties described below.
                            "qcom,kpss-acc-v1"
                            "qcom,kpss-acc-v2"
                            "rockchip,rk3066-smp"
+                           "ste,dbx500-smp"
 
        - cpu-release-addr
                Usage: required for systems that have an "enable-method"
index d3058768b23de17e4c9916c2552b1266b9263d56..c53e0b08032fe73a42f130cd790b2b1dfa753939 100644 (file)
@@ -35,7 +35,7 @@ Example:
                        device_type = "dma";
                        reg = <0x0 0x1f270000 0x0 0x10000>,
                              <0x0 0x1f200000 0x0 0x10000>,
-                             <0x0 0x1b008000 0x0 0x2000>,
+                             <0x0 0x1b000000 0x0 0x400000>,
                              <0x0 0x1054a000 0x0 0x100>;
                        interrupts = <0x0 0x82 0x4>,
                                     <0x0 0xb8 0x4>,
index cd8fe6cf536c0ddd22b94a2d7cfec0499b60c6b5..d56923cd55902fb789426fc62737a1627b2ceed8 100644 (file)
@@ -30,20 +30,27 @@ Optional properties:
 - panel@0: Node of panel connected to this DSI controller.
   See files in Documentation/devicetree/bindings/panel/ for each supported
   panel.
-- qcom,dual-panel-mode: Boolean value indicating if the DSI controller is
+- qcom,dual-dsi-mode: Boolean value indicating if the DSI controller is
   driving a panel which needs 2 DSI links.
-- qcom,master-panel: Boolean value indicating if the DSI controller is driving
+- qcom,master-dsi: Boolean value indicating if the DSI controller is driving
   the master link of the 2-DSI panel.
-- qcom,sync-dual-panel: Boolean value indicating if the DSI controller is
+- qcom,sync-dual-dsi: Boolean value indicating if the DSI controller is
   driving a 2-DSI panel whose 2 links need receive command simultaneously.
 - interrupt-parent: phandle to the MDP block if the interrupt signal is routed
   through MDP block
+- pinctrl-names: the pin control state names; should contain "default"
+- pinctrl-0: the default pinctrl state (active)
+- pinctrl-n: the "sleep" pinctrl state
+- port: DSI controller output port. This contains one endpoint subnode, with its
+  remote-endpoint set to the phandle of the connected panel's endpoint.
+  See Documentation/devicetree/bindings/graph.txt for device graph info.
 
 DSI PHY:
 Required properties:
 - compatible: Could be the following
   * "qcom,dsi-phy-28nm-hpm"
   * "qcom,dsi-phy-28nm-lp"
+  * "qcom,dsi-phy-20nm"
 - reg: Physical base address and length of the registers of PLL, PHY and PHY
   regulator
 - reg-names: The names of register regions. The following regions are required:
@@ -59,6 +66,10 @@ Required properties:
   * "iface_clk"
 - vddio-supply: phandle to vdd-io regulator device node
 
+Optional properties:
+- qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY
+  regulator is wanted.
+
 Example:
        mdss_dsi0: qcom,mdss_dsi@fd922800 {
                compatible = "qcom,mdss-dsi-ctrl";
@@ -90,9 +101,13 @@ Example:
 
                qcom,dsi-phy = <&mdss_dsi_phy0>;
 
-               qcom,dual-panel-mode;
-               qcom,master-panel;
-               qcom,sync-dual-panel;
+               qcom,dual-dsi-mode;
+               qcom,master-dsi;
+               qcom,sync-dual-dsi;
+
+               pinctrl-names = "default", "sleep";
+               pinctrl-0 = <&mdss_dsi_active>;
+               pinctrl-1 = <&mdss_dsi_suspend>;
 
                panel: panel@0 {
                        compatible = "sharp,lq101r1sx01";
@@ -101,6 +116,18 @@ Example:
 
                        power-supply = <...>;
                        backlight = <...>;
+
+                       port {
+                               panel_in: endpoint {
+                                       remote-endpoint = <&dsi0_out>;
+                               };
+                       };
+               };
+
+               port {
+                       dsi0_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
                };
        };
 
@@ -117,4 +144,6 @@ Example:
                clock-names = "iface_clk";
                clocks = <&mmcc MDSS_AHB_CLK>;
                vddio-supply = <&pma8084_l12>;
+
+               qcom,dsi-phy-regulator-ldo-mode;
        };
index c43aa53debed67622e3a7e6c3a8c138e6ddc96d7..e926239e11011c7b96e4b19d6f0f272853cb621d 100644 (file)
@@ -2,8 +2,9 @@ Qualcomm adreno/snapdragon hdmi output
 
 Required properties:
 - compatible: one of the following
+   * "qcom,hdmi-tx-8994"
    * "qcom,hdmi-tx-8084"
-   * "qcom,hdmi-tx-8074"
+   * "qcom,hdmi-tx-8974"
    * "qcom,hdmi-tx-8660"
    * "qcom,hdmi-tx-8960"
 - reg: Physical base address and length of the controller's registers
index 009f4bfa1590cc1689097954f5bc8c37e3fad095..e685610d38e26cfa439d986d5f12995593ba1daf 100644 (file)
@@ -197,9 +197,11 @@ of the following host1x client modules:
 - sor: serial output resource
 
   Required properties:
-  - compatible: For Tegra124, must contain "nvidia,tegra124-sor".  Otherwise,
-    must contain '"nvidia,<chip>-sor", "nvidia,tegra124-sor"', where <chip>
-    is tegra132.
+  - compatible: Should be:
+    - "nvidia,tegra124-sor": for Tegra124 and Tegra132
+    - "nvidia,tegra132-sor": for Tegra132
+    - "nvidia,tegra210-sor": for Tegra210
+    - "nvidia,tegra210-sor1": for Tegra210
   - reg: Physical base address and length of the controller's registers.
   - interrupts: The interrupt outputs from the controller.
   - clocks: Must contain an entry for each entry in clock-names.
index 6b1d75f1a5297f7eb76c9618103f5f4400b8f7f8..a36dfce0032e25d056b460f93af099d3d6e45a11 100644 (file)
@@ -52,10 +52,9 @@ STMicroelectronics stih4xx platforms
     See ../reset/reset.txt for details.
   - reset-names: names of the resets listed in resets property in the same
     order.
-  - ranges: to allow probing of subdevices
 
 - sti-hdmi: hdmi output block
-  must be a child of sti-tvout
+  must be a child of sti-display-subsystem
   Required properties:
   - compatible: "st,stih<chip>-hdmi";
   - reg: Physical base address of the IP registers and length of memory mapped region.
@@ -72,7 +71,7 @@ STMicroelectronics stih4xx platforms
 
 sti-hda:
   Required properties:
-  must be a child of sti-tvout
+  must be a child of sti-display-subsystem
   - compatible: "st,stih<chip>-hda"
   - reg: Physical base address of the IP registers and length of memory mapped region.
   - reg-names: names of the mapped memory regions listed in regs property in
@@ -85,7 +84,7 @@ sti-hda:
 
 sti-dvo:
   Required properties:
-  must be a child of sti-tvout
+  must be a child of sti-display-subsystem
   - compatible: "st,stih<chip>-dvo"
   - reg: Physical base address of the IP registers and length of memory mapped region.
   - reg-names: names of the mapped memory regions listed in regs property in
@@ -195,38 +194,37 @@ Example:
                        reg-names       = "tvout-reg", "hda-reg", "syscfg";
                        reset-names     = "tvout";
                        resets          = <&softreset STIH416_HDTVOUT_SOFTRESET>;
-                       ranges;
-
-                       sti-hdmi@fe85c000 {
-                               compatible      = "st,stih416-hdmi";
-                               reg             = <0xfe85c000 0x1000>, <0xfe830000 0x10000>;
-                               reg-names       = "hdmi-reg", "syscfg";
-                               interrupts      = <GIC_SPI 173 IRQ_TYPE_NONE>;
-                               interrupt-names = "irq";
-                               clock-names     = "pix", "tmds", "phy", "audio";
-                               clocks          = <&clockgen_c_vcc CLK_S_PIX_HDMI>, <&clockgen_c_vcc CLK_S_TMDS_HDMI>, <&clockgen_c_vcc CLK_S_HDMI_REJECT_PLL>, <&clockgen_b1 CLK_S_PCM_0>;
-                       };
-
-                       sti-hda@fe85a000 {
-                               compatible      = "st,stih416-hda";
-                               reg             = <0xfe85a000 0x400>, <0xfe83085c 0x4>;
-                               reg-names       = "hda-reg", "video-dacs-ctrl";
-                               clock-names     = "pix", "hddac";
-                               clocks          = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>;
-                       };
-
-                       sti-dvo@8d00400 {
-                               compatible      = "st,stih407-dvo";
-                               reg             = <0x8d00400 0x200>;
-                               reg-names       = "dvo-reg";
-                               clock-names     = "dvo_pix", "dvo",
-                                                 "main_parent", "aux_parent";
-                               clocks          = <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>,
-                                                 <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>;
-                               pinctrl-names   = "default";
-                               pinctrl-0       = <&pinctrl_dvo>;
-                               sti,panel       = <&panel_dvo>;
-                       };
+               };
+
+               sti-hdmi@fe85c000 {
+                       compatible      = "st,stih416-hdmi";
+                       reg             = <0xfe85c000 0x1000>, <0xfe830000 0x10000>;
+                       reg-names       = "hdmi-reg", "syscfg";
+                       interrupts      = <GIC_SPI 173 IRQ_TYPE_NONE>;
+                       interrupt-names = "irq";
+                       clock-names     = "pix", "tmds", "phy", "audio";
+                       clocks          = <&clockgen_c_vcc CLK_S_PIX_HDMI>, <&clockgen_c_vcc CLK_S_TMDS_HDMI>, <&clockgen_c_vcc CLK_S_HDMI_REJECT_PLL>, <&clockgen_b1 CLK_S_PCM_0>;
+               };
+
+               sti-hda@fe85a000 {
+                       compatible      = "st,stih416-hda";
+                       reg             = <0xfe85a000 0x400>, <0xfe83085c 0x4>;
+                       reg-names       = "hda-reg", "video-dacs-ctrl";
+                       clock-names     = "pix", "hddac";
+                       clocks          = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>;
+               };
+
+               sti-dvo@8d00400 {
+                       compatible      = "st,stih407-dvo";
+                       reg             = <0x8d00400 0x200>;
+                       reg-names       = "dvo-reg";
+                       clock-names     = "dvo_pix", "dvo",
+                                         "main_parent", "aux_parent";
+                       clocks          = <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>,
+                                         <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>;
+                       pinctrl-names   = "default";
+                       pinctrl-0       = <&pinctrl_dvo>;
+                       sti,panel       = <&panel_dvo>;
                };
 
                sti-hqvdp@9c000000 {
@@ -237,7 +235,7 @@ Example:
                                reset-names     = "hqvdp";
                                resets          = <&softreset STIH407_HDQVDP_SOFTRESET>;
                                st,vtg          = <&vtg_main>;
-                       };
+               };
        };
        ...
 };
index c03eec1168721bdb1c851f7c42eba34ec48f4ba7..3443e0f838dfc8a53e548527a05cf9892f2c2a92 100644 (file)
@@ -35,3 +35,6 @@ the PCIe specification.
 
                       NOTE: this only applies to the SMMU itself, not
                       masters connected upstream of the SMMU.
+
+- hisilicon,broken-prefetch-cmd
+                    : Avoid sending CMD_PREFETCH_* commands to the SMMU.
index 5d0376b8f2026ed57daabd33d684590d02ff5920..211e7785f4d240ec2ffc7258839f740e8b614b78 100644 (file)
@@ -17,7 +17,6 @@ Required properties:
               "fsl,imx6sx-usdhc"
 
 Optional properties:
-- fsl,cd-controller : Indicate to use controller internal card detection
 - fsl,wp-controller : Indicate to use controller internal write protection
 - fsl,delay-line : Specify the number of delay cells for override mode.
   This is used to set the clock delay for DLL(Delay Line) on override mode
@@ -35,7 +34,6 @@ esdhc@70004000 {
        compatible = "fsl,imx51-esdhc";
        reg = <0x70004000 0x4000>;
        interrupts = <1>;
-       fsl,cd-controller;
        fsl,wp-controller;
 };
 
diff --git a/Documentation/devicetree/bindings/panel/auo,b080uan01.txt b/Documentation/devicetree/bindings/panel/auo,b080uan01.txt
new file mode 100644 (file)
index 0000000..bae0e2b
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 8.0" WUXGA 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/lg,lg4573.txt b/Documentation/devicetree/bindings/panel/lg,lg4573.txt
new file mode 100644 (file)
index 0000000..824441f
--- /dev/null
@@ -0,0 +1,19 @@
+LG LG4573 TFT Liquid Crystal Display with SPI control bus
+
+Required properties:
+  - compatible: "lg,lg4573"
+  - reg: address of the panel on the SPI bus
+
+The panel must obey rules for SPI slave device specified in document [1].
+
+[1]: Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+
+       lcd_panel: display@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "lg,lg4573";
+               spi-max-frequency = <10000000>;
+               reg = <0>;
+       };
diff --git a/Documentation/devicetree/bindings/panel/nec,nl4827hc19-05b.txt b/Documentation/devicetree/bindings/panel/nec,nl4827hc19-05b.txt
new file mode 100644 (file)
index 0000000..8e1914d
--- /dev/null
@@ -0,0 +1,7 @@
+NEC LCD Technologies,Ltd. WQVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "nec,nl4827hc19-05b"
+
+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/okaya,rs800480t-7x0gp.txt b/Documentation/devicetree/bindings/panel/okaya,rs800480t-7x0gp.txt
new file mode 100644 (file)
index 0000000..ddf8e21
--- /dev/null
@@ -0,0 +1,7 @@
+OKAYA Electric America, Inc. RS800480T-7X0GP 7" WVGA LCD panel
+
+Required properties:
+- compatible: should be "okaya,rs800480t-7x0gp"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
index 305e3df3d9b1eb9a994c845eb28959275d2f20ed..9cf9446eaf2eac41d57251cb5853037e2b31e7c2 100644 (file)
@@ -82,6 +82,9 @@ Optional properties:
  - id: If there are multiple instance of the same type, in order to
    differentiate between each instance "id" can be used (e.g., multi-lane PCIe
    PHY). If "id" is not provided, it is set to default value of '1'.
+ - syscon-pllreset: Handle to system control region that contains the
+   CTRL_CORE_SMA_SW_0 register and register offset to the CTRL_CORE_SMA_SW_0
+   register that contains the SATA_PLL_SOFT_RESET bit. Only valid for sata_phy.
 
 This is usually a subnode of ocp2scp to which it is connected.
 
@@ -100,3 +103,16 @@ usb3phy@4a084400 {
                        "sysclk",
                        "refclk";
 };
+
+sata_phy: phy@4A096000 {
+       compatible = "ti,phy-pipe3-sata";
+       reg = <0x4A096000 0x80>, /* phy_rx */
+             <0x4A096400 0x64>, /* phy_tx */
+             <0x4A096800 0x40>; /* pll_ctrl */
+       reg-names = "phy_rx", "phy_tx", "pll_ctrl";
+       ctrl-module = <&omap_control_sata>;
+       clocks = <&sys_clkin1>, <&sata_ref_clk>;
+       clock-names = "sysclk", "refclk";
+       syscon-pllreset = <&scm_conf 0x3fc>;
+       #phy-cells = <0>;
+};
index 829bd26d17f86e753ca54f2a4750fd86db61a641..519e97c8f1b8c2029c30785cc39a97ae317e9e64 100644 (file)
@@ -3,11 +3,13 @@ MT8173 with MAX98090 CODEC
 Required properties:
 - compatible : "mediatek,mt8173-max98090"
 - mediatek,audio-codec: the phandle of the MAX98090 audio codec
+- mediatek,platform: the phandle of MT8173 ASoC platform
 
 Example:
 
        sound {
                compatible = "mediatek,mt8173-max98090";
                mediatek,audio-codec = <&max98090>;
+               mediatek,platform = <&afe>;
        };
 
index 61e98c976bd4012b99fc218b729e6fc006209b84..f205ce9e31dd5d31e981bac826e1f69e819434ca 100644 (file)
@@ -3,11 +3,13 @@ MT8173 with RT5650 RT5676 CODECS
 Required properties:
 - compatible : "mediatek,mt8173-rt5650-rt5676"
 - mediatek,audio-codec: the phandles of rt5650 and rt5676 codecs
+- mediatek,platform: the phandle of MT8173 ASoC platform
 
 Example:
 
        sound {
                compatible = "mediatek,mt8173-rt5650-rt5676";
                mediatek,audio-codec = <&rt5650 &rt5676>;
+               mediatek,platform = <&afe>;
        };
 
index f1ad9c367532437b370b412cb9f5c68b8f73c494..9c696fa66f818eb98144c628aa1b7000f96a6695 100644 (file)
@@ -3,7 +3,7 @@ Binding for Qualcomm Atheros AR7xxx/AR9xxx SPI controller
 Required properties:
 - compatible: has to be "qca,<soc-type>-spi", "qca,ar7100-spi" as fallback.
 - reg: Base address and size of the controllers memory area
-- clocks: phandle to the AHB clock.
+- clocks: phandle of the AHB clock.
 - clock-names: has to be "ahb".
 - #address-cells: <1>, as required by generic SPI binding.
 - #size-cells: <0>, also as required by generic SPI binding.
@@ -12,9 +12,9 @@ Child nodes as per the generic SPI binding.
 
 Example:
 
-       spi@1F000000 {
+       spi@1f000000 {
                compatible = "qca,ar9132-spi", "qca,ar7100-spi";
-               reg = <0x1F000000 0x10>;
+               reg = <0x1f000000 0x10>;
 
                clocks = <&pll 2>;
                clock-names = "ahb";
index d444757c4d9ec3e56c261e0adf330de187251466..bf529e77658d90d99df4790309ec39e275e1f335 100644 (file)
@@ -148,6 +148,7 @@ nintendo    Nintendo
 nokia  Nokia
 nvidia NVIDIA
 nxp    NXP Semiconductors
+okaya  Okaya Electric America, Inc.
 onnn   ON Semiconductor Corp.
 opencores      OpenCores.org
 ortustech      Ortus Technology Co., Ltd.
index 014f112e2a14e19557878a250e30438fd8f91b73..57fffe33ebfcdef2c9b52831667e147007c9454e 100644 (file)
@@ -35,11 +35,11 @@ temp1_input         Local temperature (1/1000 degree,
 temp[2-9]_input                CPU temperatures (1/1000 degree,
                        0.125 degree resolution)
 
-fan[1-4]_mode          R/W, 0/1 for manual or SmartFan mode
+pwm[1-4]_enable                R/W, 1/2 for manual or SmartFan mode
                        Setting SmartFan mode is supported only if it has been
                        previously configured by BIOS (or configuration EEPROM)
 
-fan[1-4]_pwm           R/O in SmartFan mode, R/W in manual control mode
+pwm[1-4]               R/O in SmartFan mode, R/W in manual control mode
 
 The driver checks sensor control registers and does not export the sensors
 that are not enabled. Anyway, a sensor that is enabled may actually be not
index c86f2f1ae4f6aa2d9af3e3987e8be06fd237dbef..1fec1135791d98c987105872c63b5e96589633d3 100644 (file)
@@ -119,8 +119,10 @@ ALPS Absolute Mode - Protocol Version 2
  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. For non interleaved dualpoint devices the pointingstick
-buttons get reported separately in the PSM, PSR and PSL bits.
+the DualPoint Stick. The M, R and L bits signal the combined status of both
+the pointingstick and touchpad buttons, except for Dell dualpoint devices
+where the pointingstick buttons get reported separately in the PSM, PSR
+and PSL bits.
 
 Dualpoint device -- interleaved packet format
 ---------------------------------------------
index 949de191fcdc1939c9b160eb7a809afcdbc847af..cda56df9b8a7ce591f3eb254cad1d423c0a856c5 100755 (executable)
@@ -199,7 +199,8 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "#include <linux/string.h>\n"
        buf += "#include <linux/configfs.h>\n"
        buf += "#include <linux/ctype.h>\n"
-       buf += "#include <asm/unaligned.h>\n\n"
+       buf += "#include <asm/unaligned.h>\n"
+       buf += "#include <scsi/scsi_proto.h>\n\n"
        buf += "#include <target/target_core_base.h>\n"
        buf += "#include <target/target_core_fabric.h>\n"
        buf += "#include <target/target_core_fabric_configfs.h>\n"
@@ -230,8 +231,14 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        }\n"
        buf += "        tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n"
        buf += "        tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n"
-       buf += "        ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n"
-       buf += "                                &tpg->se_tpg, SCSI_PROTOCOL_SAS);\n"
+
+       if proto_ident == "FC":
+               buf += "        ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP);\n"
+       elif proto_ident == "SAS":
+               buf += "        ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_SAS);\n"
+       elif proto_ident == "iSCSI":
+               buf += "        ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_ISCSI);\n"
+
        buf += "        if (ret < 0) {\n"
        buf += "                kfree(tpg);\n"
        buf += "                return NULL;\n"
@@ -292,7 +299,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
 
        buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n"
        buf += "        .module                         = THIS_MODULE,\n"
-       buf += "        .name                           = " + fabric_mod_name + ",\n"
+       buf += "        .name                           = \"" + fabric_mod_name + "\",\n"
        buf += "        .get_fabric_name                = " + fabric_mod_name + "_get_fabric_name,\n"
        buf += "        .tpg_get_wwn                    = " + fabric_mod_name + "_get_fabric_wwn,\n"
        buf += "        .tpg_get_tag                    = " + fabric_mod_name + "_get_tag,\n"
@@ -322,17 +329,17 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        .fabric_make_tpg                = " + fabric_mod_name + "_make_tpg,\n"
        buf += "        .fabric_drop_tpg                = " + fabric_mod_name + "_drop_tpg,\n"
        buf += "\n"
-       buf += "        .tfc_wwn_attrs                  = " + fabric_mod_name + "_wwn_attrs;\n"
+       buf += "        .tfc_wwn_attrs                  = " + fabric_mod_name + "_wwn_attrs,\n"
        buf += "};\n\n"
 
        buf += "static int __init " + fabric_mod_name + "_init(void)\n"
        buf += "{\n"
-       buf += "        return target_register_template(" + fabric_mod_name + "_ops);\n"
+       buf += "        return target_register_template(&" + fabric_mod_name + "_ops);\n"
        buf += "};\n\n"
 
        buf += "static void __exit " + fabric_mod_name + "_exit(void)\n"
        buf += "{\n"
-       buf += "        target_unregister_template(" + fabric_mod_name + "_ops);\n"
+       buf += "        target_unregister_template(&" + fabric_mod_name + "_ops);\n"
        buf += "};\n\n"
 
        buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n"
index 9c9dd5fc7affdd4fd1ba89ac7210a9251bee438f..4118b13983c260ce63c27a5cab4d3c5c64278030 100644 (file)
@@ -3592,6 +3592,15 @@ S:       Maintained
 F:     drivers/gpu/drm/rockchip/
 F:     Documentation/devicetree/bindings/video/rockchip*
 
+DRM DRIVERS FOR STI
+M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
+M:     Vincent Abriou <vincent.abriou@st.com>
+L:     dri-devel@lists.freedesktop.org
+T:     git http://git.linaro.org/people/benjamin.gaignard/kernel.git
+S:     Maintained
+F:     drivers/gpu/drm/sti
+F:     Documentation/devicetree/bindings/gpu/st,stih4xx.txt
+
 DSBR100 USB FM RADIO DRIVER
 M:     Alexey Klimov <klimov.linux@gmail.com>
 L:     linux-media@vger.kernel.org
@@ -5605,6 +5614,7 @@ F:        kernel/irq/
 IRQCHIP DRIVERS
 M:     Thomas Gleixner <tglx@linutronix.de>
 M:     Jason Cooper <jason@lakedaemon.net>
+M:     Marc Zyngier <marc.zyngier@arm.com>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
@@ -5613,11 +5623,14 @@ F:      Documentation/devicetree/bindings/interrupt-controller/
 F:     drivers/irqchip/
 
 IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
-M:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
+M:     Jiang Liu <jiang.liu@linux.intel.com>
+M:     Marc Zyngier <marc.zyngier@arm.com>
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
 F:     Documentation/IRQ-domain.txt
 F:     include/linux/irqdomain.h
 F:     kernel/irq/irqdomain.c
+F:     kernel/irq/msi.c
 
 ISAPNP
 M:     Jaroslav Kysela <perex@perex.cz>
@@ -5904,7 +5917,6 @@ S:        Supported
 F:     Documentation/s390/kvm.txt
 F:     arch/s390/include/asm/kvm*
 F:     arch/s390/kvm/
-F:     drivers/s390/kvm/
 
 KERNEL VIRTUAL MACHINE (KVM) FOR ARM
 M:     Christoffer Dall <christoffer.dall@linaro.org>
@@ -6844,6 +6856,12 @@ T:       git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
 F:     drivers/media/usb/msi2500/
 
+MSYSTEMS DISKONCHIP G3 MTD DRIVER
+M:     Robert Jarzmik <robert.jarzmik@free.fr>
+L:     linux-mtd@lists.infradead.org
+S:     Maintained
+F:     drivers/mtd/devices/docg3*
+
 MT9M032 APTINA SENSOR DRIVER
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
@@ -10901,6 +10919,15 @@ F:     drivers/block/virtio_blk.c
 F:     include/linux/virtio_*.h
 F:     include/uapi/linux/virtio_*.h
 
+VIRTIO DRIVERS FOR S390
+M:     Christian Borntraeger <borntraeger@de.ibm.com>
+M:     Cornelia Huck <cornelia.huck@de.ibm.com>
+L:     linux-s390@vger.kernel.org
+L:     virtualization@lists.linux-foundation.org
+L:     kvm@vger.kernel.org
+S:     Supported
+F:     drivers/s390/virtio/
+
 VIRTIO GPU DRIVER
 M:     David Airlie <airlied@linux.ie>
 M:     Gerd Hoffmann <kraxel@redhat.com>
index a9ad4908e8701569effc7596833e6ca513c75033..6e88c371b32f760fb8c13601d23869e91ebd0289 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc7
 NAME = Hurr durr I'ma sheep
 
 # *DOCUMENTATION*
@@ -597,6 +597,11 @@ endif # $(dot-config)
 # Defaults to vmlinux, but the arch makefile usually adds further targets
 all: vmlinux
 
+# The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default
+# values of the respective KBUILD_* variables
+ARCH_CPPFLAGS :=
+ARCH_AFLAGS :=
+ARCH_CFLAGS :=
 include arch/$(SRCARCH)/Makefile
 
 KBUILD_CFLAGS  += $(call cc-option,-fno-delete-null-pointer-checks,)
@@ -848,10 +853,10 @@ export mod_strip_cmd
 mod_compress_cmd = true
 ifdef CONFIG_MODULE_COMPRESS
   ifdef CONFIG_MODULE_COMPRESS_GZIP
-    mod_compress_cmd = gzip -n
+    mod_compress_cmd = gzip -n -f
   endif # CONFIG_MODULE_COMPRESS_GZIP
   ifdef CONFIG_MODULE_COMPRESS_XZ
-    mod_compress_cmd = xz
+    mod_compress_cmd = xz -f
   endif # CONFIG_MODULE_COMPRESS_XZ
 endif # CONFIG_MODULE_COMPRESS
 export mod_compress_cmd
index 91cf4055acab0439e564a96056012befd5fb4c36..bd4670d1b89bcabf043f13015c01b59397b73427 100644 (file)
@@ -313,11 +313,11 @@ config ARC_PAGE_SIZE_8K
 
 config ARC_PAGE_SIZE_16K
        bool "16KB"
-       depends on ARC_MMU_V3
+       depends on ARC_MMU_V3 || ARC_MMU_V4
 
 config ARC_PAGE_SIZE_4K
        bool "4KB"
-       depends on ARC_MMU_V3
+       depends on ARC_MMU_V3 || ARC_MMU_V4
 
 endchoice
 
@@ -365,6 +365,11 @@ config ARC_HAS_LLSC
        default y
        depends on !ARC_CANT_LLSC
 
+config ARC_STAR_9000923308
+       bool "Workaround for llock/scond livelock"
+       default y
+       depends on ISA_ARCV2 && SMP && ARC_HAS_LLSC
+
 config ARC_HAS_SWAPE
        bool "Insn: SWAPE (endian-swap)"
        default y
@@ -379,6 +384,10 @@ config ARC_HAS_LL64
          dest operands with 2 possible source operands.
        default y
 
+config ARC_HAS_DIV_REM
+       bool "Insn: div, divu, rem, remu"
+       default y
+
 config ARC_HAS_RTC
        bool "Local 64-bit r/o cycle counter"
        default n
index 46d87310220dadaf96be4ff08c42b240d2eb4916..8a27a48304a4c0127d97996d73c7d7dc0515d8a3 100644 (file)
@@ -36,8 +36,16 @@ cflags-$(atleast_gcc44)                      += -fsection-anchors
 cflags-$(CONFIG_ARC_HAS_LLSC)          += -mlock
 cflags-$(CONFIG_ARC_HAS_SWAPE)         += -mswape
 
+ifdef CONFIG_ISA_ARCV2
+
 ifndef CONFIG_ARC_HAS_LL64
-cflags-$(CONFIG_ISA_ARCV2)             += -mno-ll64
+cflags-y                               += -mno-ll64
+endif
+
+ifndef CONFIG_ARC_HAS_DIV_REM
+cflags-y                               += -mno-div-rem
+endif
+
 endif
 
 cflags-$(CONFIG_ARC_DW2_UNWIND)                += -fasynchronous-unwind-tables
index 070f58827a5c12c2e19469ff4280f7c69e0f36a3..c8f57b8449dcf6a36aa61cd3589b90ebba42d7ea 100644 (file)
 #define ECR_C_BIT_DTLB_LD_MISS         8
 #define ECR_C_BIT_DTLB_ST_MISS         9
 
-
 /* Auxiliary registers */
 #define AUX_IDENTITY           4
 #define AUX_INTR_VEC_BASE      0x25
-
+#define AUX_NON_VOL            0x5e
 
 /*
  * Floating Pt Registers
@@ -240,9 +239,9 @@ struct bcr_extn_xymem {
 
 struct bcr_perip {
 #ifdef CONFIG_CPU_BIG_ENDIAN
-       unsigned int start:8, pad2:8, sz:8, pad:8;
+       unsigned int start:8, pad2:8, sz:8, ver:8;
 #else
-       unsigned int pad:8, sz:8, pad2:8, start:8;
+       unsigned int ver:8, sz:8, pad2:8, start:8;
 #endif
 };
 
index 03484cb4d16d2eb4fada0095ee427726c23bd2e1..87d18ae53115596f7b64a56a4a07a572d54c3cbd 100644 (file)
 
 #define atomic_set(v, i) (((v)->counter) = (i))
 
-#ifdef CONFIG_ISA_ARCV2
-#define PREFETCHW      "       prefetchw   [%1]        \n"
-#else
-#define PREFETCHW
+#ifdef CONFIG_ARC_STAR_9000923308
+
+#define SCOND_FAIL_RETRY_VAR_DEF                                               \
+       unsigned int delay = 1, tmp;                                            \
+
+#define SCOND_FAIL_RETRY_ASM                                                   \
+       "       bz      4f                      \n"                             \
+       "   ; --- scond fail delay ---          \n"                             \
+       "       mov     %[tmp], %[delay]        \n"     /* tmp = delay */       \
+       "2:     brne.d  %[tmp], 0, 2b           \n"     /* while (tmp != 0) */  \
+       "       sub     %[tmp], %[tmp], 1       \n"     /* tmp-- */             \
+       "       rol     %[delay], %[delay]      \n"     /* delay *= 2 */        \
+       "       b       1b                      \n"     /* start over */        \
+       "4: ; --- success ---                   \n"                             \
+
+#define SCOND_FAIL_RETRY_VARS                                                  \
+         ,[delay] "+&r" (delay),[tmp] "=&r"    (tmp)                           \
+
+#else  /* !CONFIG_ARC_STAR_9000923308 */
+
+#define SCOND_FAIL_RETRY_VAR_DEF
+
+#define SCOND_FAIL_RETRY_ASM                                                   \
+       "       bnz     1b                      \n"                             \
+
+#define SCOND_FAIL_RETRY_VARS
+
 #endif
 
 #define ATOMIC_OP(op, c_op, asm_op)                                    \
 static inline void atomic_##op(int i, atomic_t *v)                     \
 {                                                                      \
-       unsigned int temp;                                              \
+       unsigned int val;                                               \
+       SCOND_FAIL_RETRY_VAR_DEF                                        \
                                                                        \
        __asm__ __volatile__(                                           \
-       "1:                             \n"                             \
-       PREFETCHW                                                       \
-       "       llock   %0, [%1]        \n"                             \
-       "       " #asm_op " %0, %0, %2  \n"                             \
-       "       scond   %0, [%1]        \n"                             \
-       "       bnz     1b              \n"                             \
-       : "=&r"(temp)   /* Early clobber, to prevent reg reuse */       \
-       : "r"(&v->counter), "ir"(i)                                     \
+       "1:     llock   %[val], [%[ctr]]                \n"             \
+       "       " #asm_op " %[val], %[val], %[i]        \n"             \
+       "       scond   %[val], [%[ctr]]                \n"             \
+       "                                               \n"             \
+       SCOND_FAIL_RETRY_ASM                                            \
+                                                                       \
+       : [val] "=&r"   (val) /* Early clobber to prevent reg reuse */  \
+         SCOND_FAIL_RETRY_VARS                                         \
+       : [ctr] "r"     (&v->counter), /* Not "m": llock only supports reg direct addr mode */  \
+         [i]   "ir"    (i)                                             \
        : "cc");                                                        \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
 static inline int atomic_##op##_return(int i, atomic_t *v)             \
 {                                                                      \
-       unsigned int temp;                                              \
+       unsigned int val;                                               \
+       SCOND_FAIL_RETRY_VAR_DEF                                        \
                                                                        \
        /*                                                              \
         * Explicit full memory barrier needed before/after as          \
@@ -58,19 +85,21 @@ static inline int atomic_##op##_return(int i, atomic_t *v)          \
        smp_mb();                                                       \
                                                                        \
        __asm__ __volatile__(                                           \
-       "1:                             \n"                             \
-       PREFETCHW                                                       \
-       "       llock   %0, [%1]        \n"                             \
-       "       " #asm_op " %0, %0, %2  \n"                             \
-       "       scond   %0, [%1]        \n"                             \
-       "       bnz     1b              \n"                             \
-       : "=&r"(temp)                                                   \
-       : "r"(&v->counter), "ir"(i)                                     \
+       "1:     llock   %[val], [%[ctr]]                \n"             \
+       "       " #asm_op " %[val], %[val], %[i]        \n"             \
+       "       scond   %[val], [%[ctr]]                \n"             \
+       "                                               \n"             \
+       SCOND_FAIL_RETRY_ASM                                            \
+                                                                       \
+       : [val] "=&r"   (val)                                           \
+         SCOND_FAIL_RETRY_VARS                                         \
+       : [ctr] "r"     (&v->counter),                                  \
+         [i]   "ir"    (i)                                             \
        : "cc");                                                        \
                                                                        \
        smp_mb();                                                       \
                                                                        \
-       return temp;                                                    \
+       return val;                                                     \
 }
 
 #else  /* !CONFIG_ARC_HAS_LLSC */
@@ -150,6 +179,9 @@ ATOMIC_OP(and, &=, and)
 #undef ATOMIC_OPS
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
+#undef SCOND_FAIL_RETRY_VAR_DEF
+#undef SCOND_FAIL_RETRY_ASM
+#undef SCOND_FAIL_RETRY_VARS
 
 /**
  * __atomic_add_unless - add unless the number is a given value
index 91694ec1ce959498fd5b4431962b03bbdf4119b7..69095da1fcfd1e35f16234aaf473896194064d38 100644 (file)
 struct pt_regs {
 
        /* Real registers */
-       long bta;       /* bta_l1, bta_l2, erbta */
+       unsigned long bta;      /* bta_l1, bta_l2, erbta */
 
-       long lp_start, lp_end, lp_count;
+       unsigned long lp_start, lp_end, lp_count;
 
-       long status32;  /* status32_l1, status32_l2, erstatus */
-       long ret;       /* ilink1, ilink2 or eret */
-       long blink;
-       long fp;
-       long r26;       /* gp */
+       unsigned long status32; /* status32_l1, status32_l2, erstatus */
+       unsigned long ret;      /* ilink1, ilink2 or eret */
+       unsigned long blink;
+       unsigned long fp;
+       unsigned long r26;      /* gp */
 
-       long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+       unsigned long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
 
-       long sp;        /* user/kernel sp depending on where we came from  */
-       long orig_r0;
+       unsigned long sp;       /* User/Kernel depending on where we came from */
+       unsigned long orig_r0;
 
        /*
         * To distinguish bet excp, syscall, irq
@@ -55,13 +55,13 @@ struct pt_regs {
                unsigned long event;
        };
 
-       long user_r25;
+       unsigned long user_r25;
 };
 #else
 
 struct pt_regs {
 
-       long orig_r0;
+       unsigned long orig_r0;
 
        union {
                struct {
@@ -76,26 +76,26 @@ struct pt_regs {
                unsigned long event;
        };
 
-       long bta;       /* bta_l1, bta_l2, erbta */
+       unsigned long bta;      /* bta_l1, bta_l2, erbta */
 
-       long user_r25;
+       unsigned long user_r25;
 
-       long r26;       /* gp */
-       long fp;
-       long sp;        /* user/kernel sp depending on where we came from  */
+       unsigned long r26;      /* gp */
+       unsigned long fp;
+       unsigned long sp;       /* user/kernel sp depending on where we came from  */
 
-       long r12;
+       unsigned long r12;
 
        /*------- Below list auto saved by h/w -----------*/
-       long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
+       unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
 
-       long blink;
-       long lp_end, lp_start, lp_count;
+       unsigned long blink;
+       unsigned long lp_end, lp_start, lp_count;
 
-       long ei, ldi, jli;
+       unsigned long ei, ldi, jli;
 
-       long ret;
-       long status32;
+       unsigned long ret;
+       unsigned long status32;
 };
 
 #endif
@@ -103,10 +103,10 @@ struct pt_regs {
 /* Callee saved registers - need to be saved only when you are scheduled out */
 
 struct callee_regs {
-       long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
+       unsigned long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
 };
 
-#define instruction_pointer(regs)      (unsigned long)((regs)->ret)
+#define instruction_pointer(regs)      ((regs)->ret)
 #define profile_pc(regs)               instruction_pointer(regs)
 
 /* return 1 if user mode or 0 if kernel mode */
@@ -142,7 +142,7 @@ struct callee_regs {
 
 static inline long regs_return_value(struct pt_regs *regs)
 {
-       return regs->r0;
+       return (long)regs->r0;
 }
 
 #endif /* !__ASSEMBLY__ */
index e1651df6a93d5bc8ab0af3a833c7c6ffd23acacc..db8c59d1eaeb760798c287a15720573ed58b9e4a 100644 (file)
 #define arch_spin_unlock_wait(x) \
        do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0)
 
+#ifdef CONFIG_ARC_HAS_LLSC
+
+/*
+ * A normal LLOCK/SCOND based system, w/o need for livelock workaround
+ */
+#ifndef CONFIG_ARC_STAR_9000923308
+
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
-       unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__;
+       unsigned int val;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 1b   \n"     /* spin while LOCKED */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+       unsigned int val, got_it = 0;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 4f   \n"     /* already LOCKED, just bail */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bnz     1b                      \n"
+       "       mov     %[got_it], 1            \n"
+       "4:                                     \n"
+       "                                       \n"
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+       smp_mb();
+
+       lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+       smp_mb();
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
+ */
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * zero means writer holds the lock exclusively, deny Reader.
+        * Otherwise grant lock to first/subseq reader
+        *
+        *      if (rw->counter > 0) {
+        *              rw->counter--;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 1b\n"     /* <= 0: spin while write locked */
+       "       sub     %[val], %[val], 1       \n"     /* reader lock */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 4f\n"     /* <= 0: already write locked, bail */
+       "       sub     %[val], %[val], 1       \n"     /* counter-- */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"     /* retry if collided with someone */
+       "       mov     %[got_it], 1            \n"
+       "                                       \n"
+       "4: ; --- done ---                      \n"
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
+        * deny writer. Otherwise if unlocked grant to writer
+        * Hence the claim that Linux rwlocks are unfair to writers.
+        * (can be starved for an indefinite time by readers).
+        *
+        *      if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
+        *              rw->counter = 0;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 1b \n"     /* while !UNLOCKED spin */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 4f \n"     /* !UNLOCKED, bail */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"     /* retry if collided with someone */
+       "       mov     %[got_it], 1            \n"
+       "                                       \n"
+       "4: ; --- done ---                      \n"
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * rw->counter++;
+        */
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       add     %[val], %[val], 1       \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter))
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       smp_mb();
+
+       rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
+
+       smp_mb();
+}
+
+#else  /* CONFIG_ARC_STAR_9000923308 */
+
+/*
+ * HS38x4 could get into a LLOCK/SCOND livelock in case of multiple overlapping
+ * coherency transactions in the SCU. The exclusive line state keeps rotating
+ * among contenting cores leading to a never ending cycle. So break the cycle
+ * by deferring the retry of failed exclusive access (SCOND). The actual delay
+ * needed is function of number of contending cores as well as the unrelated
+ * coherency traffic from other cores. To keep the code simple, start off with
+ * small delay of 1 which would suffice most cases and in case of contention
+ * double the delay. Eventually the delay is sufficient such that the coherency
+ * pipeline is drained, thus a subsequent exclusive access would succeed.
+ */
+
+#define SCOND_FAIL_RETRY_VAR_DEF                                               \
+       unsigned int delay, tmp;                                                \
+
+#define SCOND_FAIL_RETRY_ASM                                                   \
+       "   ; --- scond fail delay ---          \n"                             \
+       "       mov     %[tmp], %[delay]        \n"     /* tmp = delay */       \
+       "2:     brne.d  %[tmp], 0, 2b           \n"     /* while (tmp != 0) */  \
+       "       sub     %[tmp], %[tmp], 1       \n"     /* tmp-- */             \
+       "       rol     %[delay], %[delay]      \n"     /* delay *= 2 */        \
+       "       b       1b                      \n"     /* start over */        \
+       "                                       \n"                             \
+       "4: ; --- done ---                      \n"                             \
+
+#define SCOND_FAIL_RETRY_VARS                                                  \
+         ,[delay] "=&r" (delay), [tmp] "=&r"   (tmp)                           \
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+       unsigned int val;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 0b   \n"     /* spin while LOCKED */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bz      4f                      \n"     /* done */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val)
+         SCOND_FAIL_RETRY_VARS
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+       unsigned int val, got_it = 0;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 4f   \n"     /* already LOCKED, just bail */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bz.d    4f                      \n"
+       "       mov.z   %[got_it], 1            \n"     /* got it */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+         SCOND_FAIL_RETRY_VARS
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+       smp_mb();
+
+       lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+       smp_mb();
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
+ */
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       /*
+        * zero means writer holds the lock exclusively, deny Reader.
+        * Otherwise grant lock to first/subseq reader
+        *
+        *      if (rw->counter > 0) {
+        *              rw->counter--;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 0b\n"     /* <= 0: spin while write locked */
+       "       sub     %[val], %[val], 1       \n"     /* reader lock */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz      4f                      \n"     /* done */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 4f\n"     /* <= 0: already write locked, bail */
+       "       sub     %[val], %[val], 1       \n"     /* counter-- */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz.d    4f                      \n"
+       "       mov.z   %[got_it], 1            \n"     /* got it */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       /*
+        * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
+        * deny writer. Otherwise if unlocked grant to writer
+        * Hence the claim that Linux rwlocks are unfair to writers.
+        * (can be starved for an indefinite time by readers).
+        *
+        *      if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
+        *              rw->counter = 0;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 0b \n"     /* while !UNLOCKED spin */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz      4f                      \n"
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 4f \n"     /* !UNLOCKED, bail */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz.d    4f                      \n"
+       "       mov.z   %[got_it], 1            \n"     /* got it */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * rw->counter++;
+        */
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       add     %[val], %[val], 1       \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter))
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
+        */
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       scond   %[UNLOCKED], [%[rwlock]]\n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "r"     (__ARCH_RW_LOCK_UNLOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+#undef SCOND_FAIL_RETRY_VAR_DEF
+#undef SCOND_FAIL_RETRY_ASM
+#undef SCOND_FAIL_RETRY_VARS
+
+#endif /* CONFIG_ARC_STAR_9000923308 */
+
+#else  /* !CONFIG_ARC_HAS_LLSC */
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+       unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
 
        /*
         * This smp_mb() is technically superfluous, we only need the one
@@ -33,7 +542,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
        __asm__ __volatile__(
        "1:     ex  %0, [%1]            \n"
        "       breq  %0, %2, 1b        \n"
-       : "+&r" (tmp)
+       : "+&r" (val)
        : "r"(&(lock->slock)), "ir"(__ARCH_SPIN_LOCK_LOCKED__)
        : "memory");
 
@@ -48,26 +557,27 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
        smp_mb();
 }
 
+/* 1 - lock taken successfully */
 static inline int arch_spin_trylock(arch_spinlock_t *lock)
 {
-       unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__;
+       unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
 
        smp_mb();
 
        __asm__ __volatile__(
        "1:     ex  %0, [%1]            \n"
-       : "+r" (tmp)
+       : "+r" (val)
        : "r"(&(lock->slock))
        : "memory");
 
        smp_mb();
 
-       return (tmp == __ARCH_SPIN_LOCK_UNLOCKED__);
+       return (val == __ARCH_SPIN_LOCK_UNLOCKED__);
 }
 
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 {
-       unsigned int tmp = __ARCH_SPIN_LOCK_UNLOCKED__;
+       unsigned int val = __ARCH_SPIN_LOCK_UNLOCKED__;
 
        /*
         * RELEASE barrier: given the instructions avail on ARCv2, full barrier
@@ -77,7 +587,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
        __asm__ __volatile__(
        "       ex  %0, [%1]            \n"
-       : "+r" (tmp)
+       : "+r" (val)
        : "r"(&(lock->slock))
        : "memory");
 
@@ -90,19 +600,12 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
 /*
  * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
  *
  * The spinlock itself is contained in @counter and access to it is
  * serialized with @lock_mutex.
- *
- * Unfair locking as Writers could be starved indefinitely by Reader(s)
  */
 
-/* Would read_trylock() succeed? */
-#define arch_read_can_lock(x)  ((x)->counter > 0)
-
-/* Would write_trylock() succeed? */
-#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
-
 /* 1 - lock taken successfully */
 static inline int arch_read_trylock(arch_rwlock_t *rw)
 {
@@ -173,6 +676,11 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
        arch_spin_unlock(&(rw->lock_mutex));
 }
 
+#endif
+
+#define arch_read_can_lock(x)  ((x)->counter > 0)
+#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
+
 #define arch_read_lock_flags(lock, flags)      arch_read_lock(lock)
 #define arch_write_lock_flags(lock, flags)     arch_write_lock(lock)
 
index 662627ced4f23a966c85feffb9f9d38a4f7df10a..4e1ef5f650c6f2fc74ee1fbb09957d8d23e7b7da 100644 (file)
@@ -26,7 +26,9 @@ typedef struct {
  */
 typedef struct {
        volatile unsigned int   counter;
+#ifndef CONFIG_ARC_HAS_LLSC
        arch_spinlock_t         lock_mutex;
+#endif
 } arch_rwlock_t;
 
 #define __ARCH_RW_LOCK_UNLOCKED__      0x01000000
index 76a7739aab1c5173f397c0f8a5a79c5169489f41..0b3ef63d4a03b3ef2ff119535ee3c020641e1888 100644 (file)
 */
 struct user_regs_struct {
 
-       long pad;
+       unsigned long pad;
        struct {
-               long bta, lp_start, lp_end, lp_count;
-               long status32, ret, blink, fp, gp;
-               long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
-               long sp;
+               unsigned long bta, lp_start, lp_end, lp_count;
+               unsigned long status32, ret, blink, fp, gp;
+               unsigned long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+               unsigned long sp;
        } scratch;
-       long pad2;
+       unsigned long pad2;
        struct {
-               long r25, r24, r23, r22, r21, r20;
-               long r19, r18, r17, r16, r15, r14, r13;
+               unsigned long r25, r24, r23, r22, r21, r20;
+               unsigned long r19, r18, r17, r16, r15, r14, r13;
        } callee;
-       long efa;       /* break pt addr, for break points in delay slots */
-       long stop_pc;   /* give dbg stop_pc after ensuring brkpt trap */
+       unsigned long efa;      /* break pt addr, for break points in delay slots */
+       unsigned long stop_pc;  /* give dbg stop_pc after ensuring brkpt trap */
 };
 #endif /* !__ASSEMBLY__ */
 
index 18cc01591c96e64186a8b13c1aef5b8011091b12..cabde9dc0696479cc3a4d3074fd526cf89c85182 100644 (file)
@@ -47,6 +47,7 @@ static void read_arc_build_cfg_regs(void)
        struct bcr_perip uncached_space;
        struct bcr_generic bcr;
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
+       unsigned long perip_space;
        FIX_PTR(cpu);
 
        READ_BCR(AUX_IDENTITY, cpu->core);
@@ -56,7 +57,12 @@ static void read_arc_build_cfg_regs(void)
        cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
 
        READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
-       BUG_ON((uncached_space.start << 24) != ARC_UNCACHED_ADDR_SPACE);
+        if (uncached_space.ver < 3)
+               perip_space = uncached_space.start << 24;
+       else
+               perip_space = read_aux_reg(AUX_NON_VOL) & 0xF0000000;
+
+       BUG_ON(perip_space != ARC_UNCACHED_ADDR_SPACE);
 
        READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);
 
@@ -330,6 +336,10 @@ static void arc_chk_core_config(void)
                pr_warn("CONFIG_ARC_FPU_SAVE_RESTORE needed for working apps\n");
        else if (!cpu->extn.fpu_dp && fpu_enabled)
                panic("FPU non-existent, disable CONFIG_ARC_FPU_SAVE_RESTORE\n");
+
+       if (is_isa_arcv2() && IS_ENABLED(CONFIG_SMP) && cpu->isa.atomic &&
+           !IS_ENABLED(CONFIG_ARC_STAR_9000923308))
+               panic("llock/scond livelock workaround missing\n");
 }
 
 /*
index 3364d2bbc515471bba6478b8b34a417251ffde56..4294761a2b3e7ad3b36f5eca5bc26490e31ed61f 100644 (file)
@@ -203,34 +203,24 @@ static int arc_clkevent_set_next_event(unsigned long delta,
        return 0;
 }
 
-static void arc_clkevent_set_mode(enum clock_event_mode mode,
-                                 struct clock_event_device *dev)
+static int arc_clkevent_set_periodic(struct clock_event_device *dev)
 {
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-                /*
-                 * At X Hz, 1 sec = 1000ms -> X cycles;
-                 *                    10ms -> X / 100 cycles
-                 */
-               arc_timer_event_setup(arc_get_core_freq() / HZ);
-               break;
-       case CLOCK_EVT_MODE_ONESHOT:
-               break;
-       default:
-               break;
-       }
-
-       return;
+       /*
+        * At X Hz, 1 sec = 1000ms -> X cycles;
+        *                    10ms -> X / 100 cycles
+        */
+       arc_timer_event_setup(arc_get_core_freq() / HZ);
+       return 0;
 }
 
 static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = {
-       .name           = "ARC Timer0",
-       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
-       .mode           = CLOCK_EVT_MODE_UNUSED,
-       .rating         = 300,
-       .irq            = TIMER0_IRQ,   /* hardwired, no need for resources */
-       .set_next_event = arc_clkevent_set_next_event,
-       .set_mode       = arc_clkevent_set_mode,
+       .name                   = "ARC Timer0",
+       .features               = CLOCK_EVT_FEAT_ONESHOT |
+                                 CLOCK_EVT_FEAT_PERIODIC,
+       .rating                 = 300,
+       .irq                    = TIMER0_IRQ,   /* hardwired, no need for resources */
+       .set_next_event         = arc_clkevent_set_next_event,
+       .set_state_periodic     = arc_clkevent_set_periodic,
 };
 
 static irqreturn_t timer_irq_handler(int irq, void *dev_id)
@@ -240,7 +230,7 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id)
         * irq_set_chip_and_handler() asked for handle_percpu_devid_irq()
         */
        struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
-       int irq_reenable = evt->mode == CLOCK_EVT_MODE_PERIODIC;
+       int irq_reenable = clockevent_state_periodic(evt);
 
        /*
         * Any write to CTRL reg ACks the interrupt, we rewrite the
index 1b2b3acfed52df6f1fb0aad58fa834d3d689482d..0cab0b8a57c5665e6686e9bef843fbfa51f141fd 100644 (file)
@@ -206,7 +206,7 @@ unalignedOffby3:
        ld.ab   r6, [r1, 4]
        prefetch [r1, 28]       ;Prefetch the next read location
        ld.ab   r8, [r1,4]
-       prefetch [r3, 32]       ;Prefetch the next write location
+       prefetchw [r3, 32]      ;Prefetch the next write location
 
        SHIFT_1 (r7, r6, 8)
        or      r7, r7, r5
index 92d573c734b5b3d52dec2d8fcf6eb67cc96d16f6..365b183648154c70de1726955b9242e88d3cc60c 100644 (file)
 
 #undef PREALLOC_NOT_AVAIL
 
-#ifdef PREALLOC_NOT_AVAIL
-#define PREWRITE(A,B)  prefetchw [(A),(B)]
-#else
-#define PREWRITE(A,B)  prealloc [(A),(B)]
-#endif
-
 ENTRY(memset)
        prefetchw [r0]          ; Prefetch the write location
        mov.f   0, r2
@@ -51,9 +45,15 @@ ENTRY(memset)
 
 ;;; Convert len to Dwords, unfold x8
        lsr.f   lp_count, lp_count, 6
+
        lpnz    @.Lset64bytes
        ;; LOOP START
-       PREWRITE(r3, 64)        ;Prefetch the next write location
+#ifdef PREALLOC_NOT_AVAIL
+       prefetchw [r3, 64]      ;Prefetch the next write location
+#else
+       prealloc  [r3, 64]
+#endif
+#ifdef CONFIG_ARC_HAS_LL64
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
@@ -62,16 +62,45 @@ ENTRY(memset)
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
+#else
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+#endif
 .Lset64bytes:
 
        lsr.f   lp_count, r2, 5 ;Last remaining  max 124 bytes
        lpnz    .Lset32bytes
        ;; LOOP START
        prefetchw   [r3, 32]    ;Prefetch the next write location
+#ifdef CONFIG_ARC_HAS_LL64
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
+#else
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+#endif
 .Lset32bytes:
 
        and.f   lp_count, r2, 0x1F ;Last remaining 31 bytes
index 99f7da513a48462031a58815d48428509bad0848..e7769c3ab5f2b7793aff703ca5e926983b45ec29 100644 (file)
@@ -389,6 +389,21 @@ axs103_set_freq(unsigned int id, unsigned int fd, unsigned int od)
 
 static void __init axs103_early_init(void)
 {
+       /*
+        * AXS103 configurations for SMP/QUAD configurations share device tree
+        * which defaults to 90 MHz. However recent failures of Quad config
+        * revealed P&R timing violations so clamp it down to safe 50 MHz
+        * Instead of duplicating defconfig/DT for SMP/QUAD, add a small hack
+        *
+        * This hack is really hacky as of now. Fix it properly by getting the
+        * number of cores as return value of platform's early SMP callback
+        */
+#ifdef CONFIG_ARC_MCIP
+       unsigned int num_cores = (read_aux_reg(ARC_REG_MCIP_BCR) >> 16) & 0x3F;
+       if (num_cores > 2)
+               arc_set_core_freq(50 * 1000000);
+#endif
+
        switch (arc_get_core_freq()/1000000) {
        case 33:
                axs103_set_freq(1, 1, 1);
index 8f1e25bcecbd76273f62671e8b9afa8f193ea261..1e29ccf77ea24f56fd16f8960d2b585ccc7ce9fc 100644 (file)
                                ranges = <0 0x2000 0x2000>;
 
                                scm_conf: scm_conf@0 {
-                                       compatible = "syscon";
+                                       compatible = "syscon", "simple-bus";
                                        reg = <0x0 0x1400>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
                                ctrl-module = <&omap_control_sata>;
                                clocks = <&sys_clkin1>, <&sata_ref_clk>;
                                clock-names = "sysclk", "refclk";
+                               syscon-pllreset = <&scm_conf 0x3fc>;
                                #phy-cells = <0>;
                        };
 
index d7201333e3bcd181d0a0281b3d214a6b5e92265a..2db99433e17fdad0299b672ae87e49b6444a457e 100644 (file)
 
                mipi_phy: video-phy@10020710 {
                        compatible = "samsung,s5pv210-mipi-video-phy";
-                       reg = <0x10020710 8>;
                        #phy-cells = <1>;
+                       syscon = <&pmu_system_controller>;
                };
 
                pd_cam: cam-power-domain@10023C00 {
index e0abfc3324d11eaed33838be9c04b7f1a167f5fb..e050d85cdacddf24268870988badefca45d75a88 100644 (file)
        };
 };
 
+&cpu0 {
+       cpu0-supply = <&buck1_reg>;
+};
+
 &fimd {
        pinctrl-0 = <&lcd_en &lcd_clk &lcd_data24 &pwm0_out>;
        pinctrl-names = "default";
index 98f3ce65cb9a387a55ee588069bf42b51103317c..ba34886f8b65b6227f82ef93c530603b64910449 100644 (file)
        };
 };
 
+&cpu0 {
+       cpu0-supply = <&varm_breg>;
+};
+
 &dsi_0 {
        vddcore-supply = <&vusb_reg>;
        vddio-supply = <&vmipi_reg>;
index d4f2b11319dd10d4d7b79fa295d55e63baccff9c..775892b2cc6a8d1564f1bf463abaa19df1a859a4 100644 (file)
        };
 };
 
+&cpu0 {
+       cpu0-supply = <&vdd_arm_reg>;
+};
+
 &pinctrl_1 {
        hdmi_hpd: hdmi-hpd {
                samsung,pins = "gpx3-7";
index 10d3c173396e4cb67a2443f2d3e641c264bec168..3e5ba665d20009de0a974c9ceccb283e431b3b54 100644 (file)
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0x900>;
+                       clocks = <&clock CLK_ARM_CLK>;
+                       clock-names = "cpu";
+                       clock-latency = <160000>;
+
+                       operating-points = <
+                               1200000 1250000
+                               1000000 1150000
+                               800000  1075000
+                               500000  975000
+                               400000  975000
+                               200000  950000
+                       >;
                        cooling-min-level = <4>;
                        cooling-max-level = <2>;
                        #cooling-cells = <2>; /* min followed by max */
index dd45e6971bc35061a3b9d5b4579c6e6697ca9eca..9351296356dcc419ccb2746efa031df01bcb6462 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include "imx25.dtsi"
 
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
-       cd-gpios = <&gpio2 1 0>;
-       wp-gpios = <&gpio2 0 0>;
+       cd-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index b6478e97d6a7eb8cbb6478470d4a5e10794afaff..e6540b5cfa4cac9c06d354be4fdea73c999cd85b 100644 (file)
                        can1: can@53fe4000 {
                                compatible = "fsl,imx35-flexcan", "fsl,p1010-flexcan";
                                reg = <0x53fe4000 0x1000>;
-                               clocks = <&clks 33>;
-                               clock-names = "ipg";
+                               clocks = <&clks 33>, <&clks 33>;
+                               clock-names = "ipg", "per";
                                interrupts = <43>;
                                status = "disabled";
                        };
                        can2: can@53fe8000 {
                                compatible = "fsl,imx35-flexcan", "fsl,p1010-flexcan";
                                reg = <0x53fe8000 0x1000>;
-                               clocks = <&clks 34>;
-                               clock-names = "ipg";
+                               clocks = <&clks 34>, <&clks 34>;
+                               clock-names = "ipg", "per";
                                interrupts = <44>;
                                status = "disabled";
                        };
index 93d3ea12328c50c07cf9d7ab4d09fc952dc5a397..0f3fe29b816ebad2c77d95271e76e089437109b2 100644 (file)
@@ -98,7 +98,7 @@
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
-       cd-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio2 29 GPIO_ACTIVE_LOW>;
        bus-width = <4>;
        status = "okay";
 };
index e9337ad52f59b2159a9419b7d177f2cf6baccfe3..3bc18835fb4bbbe0e388922689a70395bb532cd6 100644 (file)
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
-       cd-gpios = <&gpio1 1 0>;
-       wp-gpios = <&gpio1 9 0>;
+       cd-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index d0e0f57eb432e9822b005e986c105fc7949e028b..53f40885c530637c1776dc6172764cf6669f918d 100644 (file)
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
-       cd-gpios = <&gpio1 1 0>;
-       wp-gpios = <&gpio1 9 0>;
+       cd-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index ab4ba39f2ed9d09d144c6536e57c89a20b542604..b0d5542ac829a53b1168c8d8501f5e1fcbd8d167 100644 (file)
 &esdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc3>;
-       cd-gpios = <&gpio3 11 0>;
-       wp-gpios = <&gpio3 12 0>;
+       cd-gpios = <&gpio3 11 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio3 12 GPIO_ACTIVE_HIGH>;
        bus-width = <8>;
        status = "okay";
 };
index 1d325576bcc04d4a119d96f7c85612f2f4bd62a2..fc89ce1e5763a2b03d5da06b38e6e3896e56dd20 100644 (file)
@@ -41,8 +41,8 @@
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
-       cd-gpios = <&gpio3 13 0>;
-       wp-gpios = <&gpio4 11 0>;
+       cd-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio4 11 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index 4f1f0e2868bf12816ec93f545a8f592e43e7f64d..e03373a58760ff79c431b40fabbb8b54e1d1039e 100644 (file)
@@ -41,8 +41,8 @@
        pinctrl-0 = <&pinctrl_esdhc2>,
                    <&pinctrl_esdhc2_cdwp>;
        vmmc-supply = <&reg_3p3v>;
-       wp-gpios = <&gpio1 2 0>;
-       cd-gpios = <&gpio1 4 0>;
+       wp-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
        status = "disabled";
 };
 
index 704bd72cbfec823da4145ead1fd6e7dc719d094b..d3e50b22064f28777bbd2a3b60f512d844ff9418 100644 (file)
 };
 
 &esdhc1 {
-       cd-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>;
        fsl,wp-controller;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
 };
 
 &esdhc2 {
-       cd-gpios = <&gpio3 25 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
        fsl,wp-controller;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc2>;
index c17d3ad6dba50213c18a9076ca15c261d6740e77..fc51b87ad2087022e8b8648c71fac18e00abb762 100644 (file)
 &esdhc2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc2>;
-       cd-gpios = <&gpio3 25 0>;
-       wp-gpios = <&gpio2 19 0>;
+       cd-gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 43cb3fd76be764cdceb08efd949f47866ebe03e9..5111f5170d5343398bab4ec60e548de07f26200b 100644 (file)
 &usdhc2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
-       cd-gpios = <&gpio1 4 0>;
-       wp-gpios = <&gpio1 2 0>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 0>;
-       wp-gpios = <&gpio7 1 0>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 78df05e9d1ce61ca7d71c0825367cd8cd3757925..d6515f7a56c427bc7a8490f932b78320f942a624 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
 #include "imx6q.dtsi"
 
 / {
 };
 
 &usdhc3 {
-       cd-gpios = <&gpio6 11 0>;
-       wp-gpios = <&gpio6 14 0>;
+       cd-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio6 14 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3
index 703539cf36d3078fa7b179fad58c26f9a72b0069..00bd63e63d0cdd47f4ffa012f572f10323a2d14f 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
 #include "imx6q.dtsi"
 
 / {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
        bus-width = <4>;
-       cd-gpios = <&gpio6 11 0>;
+       cd-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index a43abfa21e33b9b596dbab2e82b8e121baebdd00..5645d52850a7eca0f1905f7341935ae82ce99859 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
-       cd-gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
        bus-width = <4>;
-       cd-gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
index e6d9195a1da7bfb98260f0d2ca9bbd0f57de9374..f4d6ae564ead290cd9fc1e02d519573364c47af5 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
        vmmc-supply = <&reg_3p3v>;
-       cd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio4 7 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        vmmc-supply = <&reg_3p3v>;
-       cd-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio4 8 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
index 1d85de2befb3ef9c8e1257d33a34721e502e1755..a47a0399a1728da0c1293a8312f30bef082fd349 100644 (file)
 &usdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
-       cd-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
        no-1-8-v;
        status = "okay";
 };
 &usdhc2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
-       cd-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
        no-1-8-v;
        status = "okay";
index 59e5d15e3ec4bad9cc664fe0f985502cf39a1375..ff41f83551de6ee72bb6da96b24c3e3ed87d4c58 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>;
        vmmc-supply = <&reg_3p3v>;
-       cd-gpios = <&gpio1 4 0>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 2c253d6d20bd1fec6b71d18347f27ef0126e3f5e..45e7c39e80d584c73ade1523a3e4316e549c76d4 100644 (file)
@@ -1,3 +1,5 @@
+#include <dt-bindings/gpio/gpio.h>
+
 / {
        regulators {
                compatible = "simple-bus";
 &usdhc2 { /* module slot */
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
-       cd-gpios = <&gpio2 2 0>;
+       cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
index b5756c21ea1d55b791b10e6728b573a918ad78e7..4493f6e993301da96edefaac1334372cd18cf4c7 100644 (file)
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 86f03c1b147c630c43166aa9d4782da28f333519..a857d1294609a0a0670a7d3f92e446e92185b743 100644 (file)
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 4a8d97f477592316c3d9ff86cee4bc1b5c9e887f..1afe3385e2d283b7a9a2da84e37ca595ce04c13f 100644 (file)
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 62a82f3eba888f7d16f11e8dc8cac129ae4c2073..6dd0b764e036d1c51cdde3015c1a2cc56178a999 100644 (file)
                &pinctrl_hummingboard_usdhc2
        >;
        vmmc-supply = <&reg_3p3v>;
-       cd-gpios = <&gpio1 4 0>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 3af16dfe417be4bb6ec89a2f870e05f1b2df3214..d7fe6672d00cf38141aca0ea88cd807cff4b3cc7 100644 (file)
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 0>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
 &usdhc4 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc4>;
-       cd-gpios = <&gpio2 6 0>;
+       cd-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 1ce6133b67f5c65fefd2fe85d368ac455b199950..9e6ecd99b472dbcb5ce707048fc4fb4775a25a77 100644 (file)
 &usdhc2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
-       cd-gpios = <&gpio1 4 0>;
-       wp-gpios = <&gpio1 2 0>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
        status = "disabled";
 };
 
         pinctrl-names = "default";
         pinctrl-0 = <&pinctrl_usdhc3
                     &pinctrl_usdhc3_cdwp>;
-        cd-gpios = <&gpio1 27 0>;
-        wp-gpios = <&gpio1 29 0>;
+       cd-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>;
         status = "disabled";
 };
index 488a640796ac05fa50c4299185fbe71c64ef1a13..3373fd958e95c72b098ed14ea2a3228ba7903ea6 100644 (file)
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
        cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
-       wp-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_usdhc3>;
        bus-width = <4>;
        cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
-       wp-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
index 3b24b12651b2b86ee1a74d5baccca435778ddd3e..e329ca5c3322716e14a9117d7d8e1ca956c89f0b 100644 (file)
        pinctrl-0 = <&pinctrl_usdhc3>;
        pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
-       cd-gpios = <&gpio6 15 0>;
-       wp-gpios = <&gpio1 13 0>;
+       cd-gpios = <&gpio6 15 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index e00c44f6a0df888f6ecb8935ddc99b85e932ee43..782379320517735f7beb62814e0ce1944ecebb18 100644 (file)
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 0>;
-       wp-gpios = <&gpio7 1 0>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
 &usdhc4 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc4>;
-       cd-gpios = <&gpio2 6 0>;
+       cd-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index a626e6dd8022c04defdbc56171147c04027aa48b..944eb81cb2b8c03aa663a1ee7f2bcc6ca664af52 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <8>;
-       cd-gpios = <&gpio2 2 0>;
-       wp-gpios = <&gpio2 3 0>;
+       cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
        bus-width = <8>;
-       cd-gpios = <&gpio2 0 0>;
-       wp-gpios = <&gpio2 1 0>;
+       cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index f02b80b41d4fb94d9a5f690d9ddc6d89371e32f6..da08de324e9eb595db45c7cae308327d77bd33a9 100644 (file)
        pinctrl-0 = <&pinctrl_usdhc1>;
        bus-width = <4>;
        no-1-8-v;
-       cd-gpios = <&gpio7 2 0>;
+       cd-gpios = <&gpio7 2 GPIO_ACTIVE_LOW>;
        fsl,wp-controller;
        status = "okay";
 };
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
        no-1-8-v;
-       cd-gpios = <&gpio7 3 0>;
+       cd-gpios = <&gpio7 3 GPIO_ACTIVE_LOW>;
        fsl,wp-controller;
        status = "okay";
 };
index 5fb091675582e25b84026f5447d0be604f9266ac..9e096d811bedac74d09c6ebf584665ff1ac6fead 100644 (file)
@@ -9,6 +9,8 @@
  *
  */
 
+#include <dt-bindings/gpio/gpio.h>
+
 / {
        regulators {
                compatible = "simple-bus";
 &usdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
-       cd-gpios = <&gpio1 2 0>;
+       cd-gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio3 9 0>;
+       cd-gpios = <&gpio3 9 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index e6d13592080d7c701056c2f6a73326aa11e715b5..b57033e8c633187a5f52c367a788f46196967fdc 100644 (file)
                        interrupt-names = "msi";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
-                       interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
-                                       <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
-                                       <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-                                       <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-map = <0 0 0 1 &gpc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 2 &gpc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 3 &gpc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 4 &gpc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clks IMX6QDL_CLK_PCIE_AXI>,
                                 <&clks IMX6QDL_CLK_LVDS1_GATE>,
                                 <&clks IMX6QDL_CLK_PCIE_REF_125M>;
index 945887d3fdb35a6588155590474479901a45671f..b84dff2e94ea1e4e44c15a054d90e67f9d06bde6 100644 (file)
        pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
        bus-width = <8>;
-       cd-gpios = <&gpio4 7 0>;
-       wp-gpios = <&gpio4 6 0>;
+       cd-gpios = <&gpio4 7 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_usdhc2>;
        pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
-       cd-gpios = <&gpio5 0 0>;
-       wp-gpios = <&gpio4 29 0>;
+       cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_usdhc3>;
        pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
-       cd-gpios = <&gpio3 22 0>;
+       cd-gpios = <&gpio3 22 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index e3c0b63c22056764f93dbecfc2b9500770a6343c..115f3fd78971868ad7025fbb0f46c17c4252e574 100644 (file)
@@ -49,7 +49,7 @@
        pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
        bus-width = <8>;
-       cd-gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio7 10 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
        keep-power-in-suspend;
        enable-sdio-wakeup;
@@ -61,7 +61,7 @@
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc4>;
        bus-width = <8>;
-       cd-gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio7 11 GPIO_ACTIVE_LOW>;
        no-1-8-v;
        keep-power-in-suspend;
        enable-sdio-wakup;
index cef04cef3a807f44efdc6a44fb754e0eb4b40b1e..ac88c3467078ec92971324395101b7db785da005 100644 (file)
        pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
        bus-width = <8>;
-       cd-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>;
        keep-power-in-suspend;
        enable-sdio-wakeup;
 &usdhc4 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc4>;
-       cd-gpios = <&gpio6 21 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio6 21 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio6 20 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
index 4d1a4b977d8492c62085f87ecff7ad29704eb4ad..fdd1d7c9a5cc2608ac047f088f62e394d88db124 100644 (file)
 &usdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
-       cd-gpios = <&gpio5 0 0>;
-       wp-gpios = <&gpio5 1 0>;
+       cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
        enable-sdio-wakeup;
        keep-power-in-suspend;
        status = "okay";
index 4773d6af66a0ad8bfa2296a53737e0d82f3698ce..d56d68fe7ffc65788dee9867630433f263f08293 100644 (file)
@@ -13,9 +13,8 @@ clocks {
                #clock-cells = <0>;
                compatible = "ti,keystone,main-pll-clock";
                clocks = <&refclksys>;
-               reg = <0x02620350 4>, <0x02310110 4>;
-               reg-names = "control", "multiplier";
-               fixed-postdiv = <2>;
+               reg = <0x02620350 4>, <0x02310110 4>, <0x02310108 4>;
+               reg-names = "control", "multiplier", "post-divider";
        };
 
        papllclk: papllclk@2620358 {
index 1b6494fbdb91b9301c607652efbd9a9fb34a9f36..675fb8e492c6aa0478a6d5df01b30fbe1e281b7d 100644 (file)
                                        <GIC_SPI 376 IRQ_TYPE_EDGE_RISING>;
                        };
                };
+
+               mdio: mdio@24200f00 {
+                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x24200f00 0x100>;
+                       status = "disabled";
+                       clocks = <&clkcpgmac>;
+                       clock-names = "fck";
+                       bus_freq        = <2500000>;
+               };
                /include/ "k2e-netcp.dtsi"
        };
 };
-
-&mdio {
-       reg = <0x24200f00 0x100>;
-};
index d5adee3c006758076c4c6a8f693022893b29f4da..af9b7190533aa9c47bf9cd17a63a1d08901ede7d 100644 (file)
@@ -22,9 +22,8 @@ clocks {
                #clock-cells = <0>;
                compatible = "ti,keystone,main-pll-clock";
                clocks = <&refclksys>;
-               reg = <0x02620350 4>, <0x02310110 4>;
-               reg-names = "control", "multiplier";
-               fixed-postdiv = <2>;
+               reg = <0x02620350 4>, <0x02310110 4>, <0x02310108 4>;
+               reg-names = "control", "multiplier", "post-divider";
        };
 
        papllclk: papllclk@2620358 {
index ae6472407b2277012096d733bb80951592555d03..d0810a5f296857394397c7f1c60bffa0011bb6e1 100644 (file)
                        #gpio-cells = <2>;
                        gpio,syscon-dev = <&devctrl 0x25c>;
                };
+
+               mdio: mdio@02090300 {
+                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x02090300 0x100>;
+                       status = "disabled";
+                       clocks = <&clkcpgmac>;
+                       clock-names = "fck";
+                       bus_freq        = <2500000>;
+               };
                /include/ "k2hk-netcp.dtsi"
        };
 };
index eb1e3e29f073856d76a1e47130bdd3639726d648..ef8464bb11ffd9833e24f2dbe4d61d348065dd1c 100644 (file)
@@ -22,9 +22,8 @@ clocks {
                #clock-cells = <0>;
                compatible = "ti,keystone,main-pll-clock";
                clocks = <&refclksys>;
-               reg = <0x02620350 4>, <0x02310110 4>;
-               reg-names = "control", "multiplier";
-               fixed-postdiv = <2>;
+               reg = <0x02620350 4>, <0x02310110 4>, <0x02310108 4>;
+               reg-names = "control", "multiplier", "post-divider";
        };
 
        papllclk: papllclk@2620358 {
index 0e007483615e4f097bb747a2d882b2e2d3a030aa..49fd414f680c93ab50cf0dae72d2e9261181da21 100644 (file)
@@ -29,7 +29,6 @@
        };
 
        soc {
-
                /include/ "k2l-clocks.dtsi"
 
                uart2: serial@02348400 {
                        #gpio-cells = <2>;
                        gpio,syscon-dev = <&devctrl 0x24c>;
                };
+
+               mdio: mdio@26200f00 {
+                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x26200f00 0x100>;
+                       status = "disabled";
+                       clocks = <&clkcpgmac>;
+                       clock-names = "fck";
+                       bus_freq        = <2500000>;
+               };
                /include/ "k2l-netcp.dtsi"
        };
 };
        /* Pin muxed. Enabled and configured by Bootloader */
        status = "disabled";
 };
-
-&mdio {
-       reg = <0x26200f00 0x100>;
-};
index e7a6f6deabb6c0d89d4ca1e2c2ae63639249d010..72816d65f7ec3fcf5d7c47ce792ae57db369754b 100644 (file)
                                  1 0 0x21000A00 0x00000100>;
                };
 
-               mdio: mdio@02090300 {
-                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       reg             = <0x02090300 0x100>;
-                       status = "disabled";
-                       clocks = <&clkpa>;
-                       clock-names = "fck";
-                       bus_freq        = <2500000>;
-               };
-
                kirq0: keystone_irq@26202a0 {
                        compatible = "ti,keystone-irq";
                        interrupts = <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>;
index 11a7963be0035a002fa77c2bec6809b34444e584..2390f387c27163bb76e918bb73e26966bee7fb48 100644 (file)
@@ -51,7 +51,8 @@
                                };
 
                                scm_conf: scm_conf@270 {
-                                       compatible = "syscon";
+                                       compatible = "syscon",
+                                                    "simple-bus";
                                        reg = <0x270 0x240>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
index 7d31c6ff246f47b14afd5eeb332d01a955faef35..abc4473e6f8a17e51d5e66416be089ab24d7b472 100644 (file)
                                };
 
                                omap4_padconf_global: omap4_padconf_global@5a0 {
-                                       compatible = "syscon";
+                                       compatible = "syscon",
+                                                    "simple-bus";
                                        reg = <0x5a0 0x170>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
index c8fd648a7108515def0e9492936fd3760f156579..b1a1263e600168291091a963f9f56aefc87fd59e 100644 (file)
                                };
 
                                omap5_padconf_global: omap5_padconf_global@5a0 {
-                                       compatible = "syscon";
+                                       compatible = "syscon",
+                                                    "simple-bus";
                                        reg = <0x5a0 0xec>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
index a75f3289e653ab2973e2d7dd1cb12c8a12724451..b8f81fb418ce60039ad4e8e04f2892ca34d26bc8 100644 (file)
 #include "skeleton.dtsi"
 
 / {
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               enable-method = "ste,dbx500-smp";
+
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&CPU0>;
+                               };
+                               core1 {
+                                       cpu = <&CPU1>;
+                               };
+                       };
+               };
+               CPU0: cpu@300 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a9";
+                       reg = <0x300>;
+               };
+               CPU1: cpu@301 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a9";
+                       reg = <0x301>;
+               };
+       };
+
        soc {
                #address-cells = <1>;
                #size-cells = <1>;
                interrupt-parent = <&intc>;
                ranges;
 
-               cpus {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       cpu-map {
-                               cluster0 {
-                                       core0 {
-                                               cpu = <&CPU0>;
-                                       };
-                                       core1 {
-                                               cpu = <&CPU1>;
-                                       };
-                               };
-                       };
-                       CPU0: cpu@0 {
-                               device_type = "cpu";
-                               compatible = "arm,cortex-a9";
-                               reg = <0>;
-                       };
-                       CPU1: cpu@1 {
-                               device_type = "cpu";
-                               compatible = "arm,cortex-a9";
-                               reg = <1>;
-                       };
-               };
-
                ptm@801ae000 {
                        compatible = "arm,coresight-etm3x", "arm,primecell";
                        reg = <0x801ae000 0x1000>;
index 3d0b8755caeee62f77ac214d343ab40cebba2ce0..3d25dba143a5d7f4a254460343161ad5e9c4e6ff 100644 (file)
@@ -17,6 +17,7 @@
        };
 
        aliases {
+               serial1 = &uart1;
                stmpe-i2c0 = &stmpe0;
                stmpe-i2c1 = &stmpe1;
        };
index 85d3b95dfdba55b543aa0f66733df936d5074abc..3c140d05f7966c79ae0a0e9ed323baaf2a80adb6 100644 (file)
                bootargs = "root=/dev/ram0 console=ttyAMA1,115200n8 earlyprintk";
        };
 
+       aliases {
+               serial1 = &uart1;
+       };
+
        src@101e0000 {
                /* These chrystal drivers are not used on this board */
                disable-sxtalo;
index 9a5f2ba139b7376018d8e48a6263e2ad711fa865..ef794a33b4dcc2ddf2076a0e27ff948e01d67d44 100644 (file)
                        clock-names = "uartclk", "apb_pclk";
                        pinctrl-names = "default";
                        pinctrl-0 = <&uart0_default_mux>;
+                       status = "disabled";
                };
 
                uart1: uart@101fb000 {
index 9504e779028834deaa29731f24c9f4adf63aa24a..3eaf8fbaf60346330215f43bbfd2a28bd4f10857 100644 (file)
@@ -124,14 +124,14 @@ CONFIG_REGULATOR_S2MPS11=y
 CONFIG_REGULATOR_S5M8767=y
 CONFIG_REGULATOR_TPS65090=y
 CONFIG_DRM=y
-CONFIG_DRM_PTN3460=y
-CONFIG_DRM_PS8622=y
+CONFIG_DRM_NXP_PTN3460=y
+CONFIG_DRM_PARADE_PS8622=y
 CONFIG_DRM_EXYNOS=y
 CONFIG_DRM_EXYNOS_FIMD=y
 CONFIG_DRM_EXYNOS_DSI=y
 CONFIG_DRM_EXYNOS_HDMI=y
 CONFIG_DRM_PANEL_SIMPLE=y
-CONFIG_DRM_PANEL_S6E8AA0=y
+CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y
 CONFIG_FB_SIMPLE=y
 CONFIG_EXYNOS_VIDEO=y
 CONFIG_EXYNOS_MIPI_DSI=y
index 5fd8df6f50ea0c4f9d86cbf0b95364c159c17fb1..6413390212fec8506a5e05c3dc79725a85ce2826 100644 (file)
@@ -429,15 +429,15 @@ CONFIG_VIDEO_RENESAS_VSP1=m
 CONFIG_VIDEO_ADV7180=m
 CONFIG_VIDEO_ML86V7667=m
 CONFIG_DRM=y
-CONFIG_DRM_PTN3460=m
-CONFIG_DRM_PS8622=m
+CONFIG_DRM_NXP_PTN3460=m
+CONFIG_DRM_PARADE_PS8622=m
 CONFIG_DRM_EXYNOS=m
 CONFIG_DRM_EXYNOS_DSI=y
 CONFIG_DRM_EXYNOS_FIMD=y
 CONFIG_DRM_EXYNOS_HDMI=y
 CONFIG_DRM_RCAR_DU=m
 CONFIG_DRM_TEGRA=y
-CONFIG_DRM_PANEL_S6E8AA0=m
+CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m
 CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_FB_ARMCLCD=y
 CONFIG_FB_WM8505=y
index 92828a1dec80c1c33d051d9b76063727598495d5..b48dd4f37f8067e781ee3e135ed7aff27940371f 100644 (file)
@@ -61,6 +61,7 @@ work_pending:
        movlt   scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)
        ldmia   sp, {r0 - r6}                   @ have to reload r0 - r6
        b       local_restart                   @ ... and off we go
+ENDPROC(ret_fast_syscall)
 
 /*
  * "slow" syscall return path.  "why" tells us if this was a real syscall.
index bd755d97e459d77ff05cc8a1264f336c58c1b598..29e2991465cb27b579f729deec65e2293a0a04b5 100644 (file)
@@ -399,6 +399,9 @@ ENTRY(secondary_startup)
        sub     lr, r4, r5                      @ mmu has been enabled
        add     r3, r7, lr
        ldrd    r4, [r3, #0]                    @ get secondary_data.pgdir
+ARM_BE8(eor    r4, r4, r5)                     @ Swap r5 and r4 in BE:
+ARM_BE8(eor    r5, r4, r5)                     @ it can be done in 3 steps
+ARM_BE8(eor    r4, r4, r5)                     @ without using a temp reg.
        ldr     r8, [r3, #8]                    @ get secondary_data.swapper_pg_dir
        badr    lr, __enable_mmu                @ return address
        mov     r13, r12                        @ __secondary_switched address
index efe17dd9b9218b7ef16299700a0f2a6d74ca61c1..54a5aeab988d3526657b8e3089942ca8cfe4fe5e 100644 (file)
@@ -296,7 +296,6 @@ static bool tk_is_cntvct(const struct timekeeper *tk)
  */
 void update_vsyscall(struct timekeeper *tk)
 {
-       struct timespec xtime_coarse;
        struct timespec64 *wtm = &tk->wall_to_monotonic;
 
        if (!cntvct_ok) {
@@ -308,10 +307,10 @@ void update_vsyscall(struct timekeeper *tk)
 
        vdso_write_begin(vdso_data);
 
-       xtime_coarse = __current_kernel_time();
        vdso_data->tk_is_cntvct                 = tk_is_cntvct(tk);
-       vdso_data->xtime_coarse_sec             = xtime_coarse.tv_sec;
-       vdso_data->xtime_coarse_nsec            = xtime_coarse.tv_nsec;
+       vdso_data->xtime_coarse_sec             = tk->xtime_sec;
+       vdso_data->xtime_coarse_nsec            = (u32)(tk->tkr_mono.xtime_nsec >>
+                                                       tk->tkr_mono.shift);
        vdso_data->wtm_clock_sec                = wtm->tv_sec;
        vdso_data->wtm_clock_nsec               = wtm->tv_nsec;
 
index 6001f1c9d136f45fabd7d61e97638855d0beb46a..4a87e86dec45d1546153ca0ebb7310bbd5f82d93 100644 (file)
@@ -146,9 +146,8 @@ static __init int exynos4_pm_init_power_domain(void)
                pd->base = of_iomap(np, 0);
                if (!pd->base) {
                        pr_warn("%s: failed to map memory\n", __func__);
-                       kfree(pd->pd.name);
+                       kfree_const(pd->pd.name);
                        kfree(pd);
-                       of_node_put(np);
                        continue;
                }
 
index d78c12e7cb5e1ace5f79a9d28f45321e809dea24..486cc4ded1906670c053f110bb09aeee34ea7fa3 100644 (file)
@@ -2373,6 +2373,9 @@ static int of_dev_hwmod_lookup(struct device_node *np,
  * registers.  This address is needed early so the OCP registers that
  * are part of the device's address space can be ioremapped properly.
  *
+ * If SYSC access is not needed, the registers will not be remapped
+ * and non-availability of MPU access is not treated as an error.
+ *
  * Returns 0 on success, -EINVAL if an invalid hwmod is passed, and
  * -ENXIO on absent or invalid register target address space.
  */
@@ -2387,6 +2390,11 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
 
        _save_mpu_port_index(oh);
 
+       /* if we don't need sysc access we don't need to ioremap */
+       if (!oh->class->sysc)
+               return 0;
+
+       /* we can't continue without MPU PORT if we need sysc access */
        if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
                return -ENXIO;
 
@@ -2396,8 +2404,10 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
                         oh->name);
 
                /* Extract the IO space from device tree blob */
-               if (!np)
+               if (!np) {
+                       pr_err("omap_hwmod: %s: no dt node\n", oh->name);
                        return -ENXIO;
+               }
 
                va_start = of_iomap(np, index + oh->mpu_rt_idx);
        } else {
@@ -2456,13 +2466,11 @@ static int __init _init(struct omap_hwmod *oh, void *data)
                                oh->name, np->name);
        }
 
-       if (oh->class->sysc) {
-               r = _init_mpu_rt_base(oh, NULL, index, np);
-               if (r < 0) {
-                       WARN(1, "omap_hwmod: %s: doesn't have mpu register target base\n",
-                            oh->name);
-                       return 0;
-               }
+       r = _init_mpu_rt_base(oh, NULL, index, np);
+       if (r < 0) {
+               WARN(1, "omap_hwmod: %s: doesn't have mpu register target base\n",
+                    oh->name);
+               return 0;
        }
 
        r = _init_clocks(oh, NULL);
index 2606c6608bd8b5c72793cbcc11acc1e2ccee4301..562247bced496bc085f75cb65f5061f8ec2be6c1 100644 (file)
@@ -827,8 +827,7 @@ static struct omap_hwmod_class_sysconfig dra7xx_gpmc_sysc = {
        .syss_offs      = 0x0014,
        .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
                           SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
        .sysc_fields    = &omap_hwmod_sysc_type1,
 };
 
@@ -844,7 +843,7 @@ static struct omap_hwmod dra7xx_gpmc_hwmod = {
        .class          = &dra7xx_gpmc_hwmod_class,
        .clkdm_name     = "l3main1_clkdm",
        /* Skip reset for CONFIG_OMAP_GPMC_DEBUG for bootloader timings */
-       .flags          = HWMOD_SWSUP_SIDLE | DEBUG_OMAP_GPMC_HWMOD_FLAGS,
+       .flags          = DEBUG_OMAP_GPMC_HWMOD_FLAGS,
        .main_clk       = "l3_iclk_div",
        .prcm = {
                .omap4 = {
index 4550d247e308be128b439b0735d853f4745f3618..c011e2296cb1e681863338972c6ce79f836bb6be 100644 (file)
@@ -74,32 +74,52 @@ struct jit_ctx {
 
 int bpf_jit_enable __read_mostly;
 
-static u64 jit_get_skb_b(struct sk_buff *skb, unsigned offset)
+static inline int call_neg_helper(struct sk_buff *skb, int offset, void *ret,
+                     unsigned int size)
+{
+       void *ptr = bpf_internal_load_pointer_neg_helper(skb, offset, size);
+
+       if (!ptr)
+               return -EFAULT;
+       memcpy(ret, ptr, size);
+       return 0;
+}
+
+static u64 jit_get_skb_b(struct sk_buff *skb, int offset)
 {
        u8 ret;
        int err;
 
-       err = skb_copy_bits(skb, offset, &ret, 1);
+       if (offset < 0)
+               err = call_neg_helper(skb, offset, &ret, 1);
+       else
+               err = skb_copy_bits(skb, offset, &ret, 1);
 
        return (u64)err << 32 | ret;
 }
 
-static u64 jit_get_skb_h(struct sk_buff *skb, unsigned offset)
+static u64 jit_get_skb_h(struct sk_buff *skb, int offset)
 {
        u16 ret;
        int err;
 
-       err = skb_copy_bits(skb, offset, &ret, 2);
+       if (offset < 0)
+               err = call_neg_helper(skb, offset, &ret, 2);
+       else
+               err = skb_copy_bits(skb, offset, &ret, 2);
 
        return (u64)err << 32 | ntohs(ret);
 }
 
-static u64 jit_get_skb_w(struct sk_buff *skb, unsigned offset)
+static u64 jit_get_skb_w(struct sk_buff *skb, int offset)
 {
        u32 ret;
        int err;
 
-       err = skb_copy_bits(skb, offset, &ret, 4);
+       if (offset < 0)
+               err = call_neg_helper(skb, offset, &ret, 4);
+       else
+               err = skb_copy_bits(skb, offset, &ret, 4);
 
        return (u64)err << 32 | ntohl(ret);
 }
@@ -536,9 +556,6 @@ static int build_body(struct jit_ctx *ctx)
                case BPF_LD | BPF_B | BPF_ABS:
                        load_order = 0;
 load:
-                       /* the interpreter will deal with the negative K */
-                       if ((int)k < 0)
-                               return -ENOTSUPP;
                        emit_mov_i(r_off, k, ctx);
 load_common:
                        ctx->seen |= SEEN_DATA | SEEN_CALL;
@@ -547,12 +564,24 @@ load_common:
                                emit(ARM_SUB_I(r_scratch, r_skb_hl,
                                               1 << load_order), ctx);
                                emit(ARM_CMP_R(r_scratch, r_off), ctx);
-                               condt = ARM_COND_HS;
+                               condt = ARM_COND_GE;
                        } else {
                                emit(ARM_CMP_R(r_skb_hl, r_off), ctx);
                                condt = ARM_COND_HI;
                        }
 
+                       /*
+                        * test for negative offset, only if we are
+                        * currently scheduled to take the fast
+                        * path. this will update the flags so that
+                        * the slowpath instruction are ignored if the
+                        * offset is negative.
+                        *
+                        * for loard_order == 0 the HI condition will
+                        * make loads at offset 0 take the slow path too.
+                        */
+                       _emit(condt, ARM_CMP_I(r_off, 0), ctx);
+
                        _emit(condt, ARM_ADD_R(r_scratch, r_off, r_skb_data),
                              ctx);
 
@@ -860,9 +889,11 @@ b_epilogue:
                        off = offsetof(struct sk_buff, vlan_tci);
                        emit(ARM_LDRH_I(r_A, r_skb, off), ctx);
                        if (code == (BPF_ANC | SKF_AD_VLAN_TAG))
-                               OP_IMM3(ARM_AND, r_A, r_A, VLAN_VID_MASK, ctx);
-                       else
-                               OP_IMM3(ARM_AND, r_A, r_A, VLAN_TAG_PRESENT, ctx);
+                               OP_IMM3(ARM_AND, r_A, r_A, ~VLAN_TAG_PRESENT, ctx);
+                       else {
+                               OP_IMM3(ARM_LSR, r_A, r_A, 12, ctx);
+                               OP_IMM3(ARM_AND, r_A, r_A, 0x1, ctx);
+                       }
                        break;
                case BPF_ANC | SKF_AD_QUEUE:
                        ctx->seen |= SEEN_SKB;
index 9d259d94e429c4cc493542ad4cf238a513b13743..1160434eece0509c3797733b49e8fcb1262e42e7 100644 (file)
@@ -14,7 +14,7 @@ VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
 VDSO_LDFLAGS += -nostdlib -shared
 VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
 VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--build-id)
-VDSO_LDFLAGS += $(call cc-option, -fuse-ld=bfd)
+VDSO_LDFLAGS += $(call cc-ldoption, -fuse-ld=bfd)
 
 obj-$(CONFIG_VDSO) += vdso.o
 extra-$(CONFIG_VDSO) += vdso.lds
index 0689c3fb56e3d84fe3ed7790f4a6b25835c86555..58093edeea2e5b7513321ff5ddfcb305ac873638 100644 (file)
                        device_type = "dma";
                        reg = <0x0 0x1f270000 0x0 0x10000>,
                              <0x0 0x1f200000 0x0 0x10000>,
-                             <0x0 0x1b008000 0x0 0x2000>,
+                             <0x0 0x1b000000 0x0 0x400000>,
                              <0x0 0x1054a000 0x0 0x100>;
                        interrupts = <0x0 0x82 0x4>,
                                     <0x0 0xb8 0x4>,
index 9d4aa18f2a825256537a7d7e33c606d89d003ee7..e8ca6eaedd0252e2056530d71d519f423931d323 100644 (file)
@@ -122,12 +122,12 @@ static int __init uefi_init(void)
 
        /* Show what we know for posterity */
        c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor),
-                            sizeof(vendor));
+                            sizeof(vendor) * sizeof(efi_char16_t));
        if (c16) {
                for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
                        vendor[i] = c16[i];
                vendor[i] = '\0';
-               early_memunmap(c16, sizeof(vendor));
+               early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
        }
 
        pr_info("EFI v%u.%.02u by %s\n",
index f860bfda454afb9de7007684ba60eaf7f375e130..e16351819fed9ada8575f117c4777232da0d72b9 100644 (file)
@@ -585,7 +585,8 @@ ENDPROC(el0_irq)
  *
  */
 ENTRY(cpu_switch_to)
-       add     x8, x0, #THREAD_CPU_CONTEXT
+       mov     x10, #THREAD_CPU_CONTEXT
+       add     x8, x0, x10
        mov     x9, sp
        stp     x19, x20, [x8], #16             // store callee-saved registers
        stp     x21, x22, [x8], #16
@@ -594,7 +595,7 @@ ENTRY(cpu_switch_to)
        stp     x27, x28, [x8], #16
        stp     x29, x9, [x8], #16
        str     lr, [x8]
-       add     x8, x1, #THREAD_CPU_CONTEXT
+       add     x8, x1, x10
        ldp     x19, x20, [x8], #16             // restore callee-saved registers
        ldp     x21, x22, [x8], #16
        ldp     x23, x24, [x8], #16
index 240b75c0e94fdc435a672b740b08d4a848915295..463fa2e7e34c10ba56f2cd4a10e208062feff3d9 100644 (file)
@@ -61,7 +61,7 @@ void __init init_IRQ(void)
 static bool migrate_one_irq(struct irq_desc *desc)
 {
        struct irq_data *d = irq_desc_get_irq_data(desc);
-       const struct cpumask *affinity = d->affinity;
+       const struct cpumask *affinity = irq_data_get_affinity_mask(d);
        struct irq_chip *c;
        bool ret = false;
 
@@ -81,7 +81,7 @@ static bool migrate_one_irq(struct irq_desc *desc)
        if (!c->irq_set_affinity)
                pr_debug("IRQ%u: unable to set affinity\n", d->irq);
        else if (c->irq_set_affinity(d, affinity, false) == IRQ_SET_MASK_OK && ret)
-               cpumask_copy(d->affinity, affinity);
+               cpumask_copy(irq_data_get_affinity_mask(d), affinity);
 
        return ret;
 }
index 1670f15ef69e34972986081deb9b1f87b0bb2bb3..948f0ad2de231b5e3f5efa62e204162cadf26503 100644 (file)
@@ -168,7 +168,8 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitely for the right codes here.
                 */
-               if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+               if (from->si_signo == SIGBUS &&
+                   (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
                        err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
 #endif
                break;
@@ -201,8 +202,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
 
 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 {
-       memset(to, 0, sizeof *to);
-
        if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) ||
            copy_from_user(to->_sifields._pad,
                           from->_sifields._pad, SI_PAD_SIZE))
index ec37ab3f524f303419d2cc3a82b79c119e61de1d..97bc68f4c689f28eac7188f5e0b792b5293c37da 100644 (file)
@@ -199,16 +199,15 @@ up_fail:
  */
 void update_vsyscall(struct timekeeper *tk)
 {
-       struct timespec xtime_coarse;
        u32 use_syscall = strcmp(tk->tkr_mono.clock->name, "arch_sys_counter");
 
        ++vdso_data->tb_seq_count;
        smp_wmb();
 
-       xtime_coarse = __current_kernel_time();
        vdso_data->use_syscall                  = use_syscall;
-       vdso_data->xtime_coarse_sec             = xtime_coarse.tv_sec;
-       vdso_data->xtime_coarse_nsec            = xtime_coarse.tv_nsec;
+       vdso_data->xtime_coarse_sec             = tk->xtime_sec;
+       vdso_data->xtime_coarse_nsec            = tk->tkr_mono.xtime_nsec >>
+                                                       tk->tkr_mono.shift;
        vdso_data->wtm_clock_sec                = tk->wall_to_monotonic.tv_sec;
        vdso_data->wtm_clock_nsec               = tk->wall_to_monotonic.tv_nsec;
 
index d0f771be9e96eda02c1045bbb5702cc9b9f74b8d..a124c55733dbf7dc19e61aacbf74671ff149de83 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <mach/pm.h>
 
+static bool disable_cpu_idle_poll;
 
 static cycle_t read_cycle_count(struct clocksource *cs)
 {
@@ -80,45 +81,45 @@ static int comparator_next_event(unsigned long delta,
        return 0;
 }
 
-static void comparator_mode(enum clock_event_mode mode,
-               struct clock_event_device *evdev)
+static int comparator_shutdown(struct clock_event_device *evdev)
 {
-       switch (mode) {
-       case CLOCK_EVT_MODE_ONESHOT:
-               pr_debug("%s: start\n", evdev->name);
-               /* FALLTHROUGH */
-       case CLOCK_EVT_MODE_RESUME:
+       pr_debug("%s: %s\n", __func__, evdev->name);
+       sysreg_write(COMPARE, 0);
+
+       if (disable_cpu_idle_poll) {
+               disable_cpu_idle_poll = false;
                /*
-                * If we're using the COUNT and COMPARE registers we
-                * need to force idle poll.
+                * Only disable idle poll if we have forced that
+                * in a previous call.
                 */
-               cpu_idle_poll_ctrl(true);
-               break;
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_SHUTDOWN:
-               sysreg_write(COMPARE, 0);
-               pr_debug("%s: stop\n", evdev->name);
-               if (evdev->mode == CLOCK_EVT_MODE_ONESHOT ||
-                   evdev->mode == CLOCK_EVT_MODE_RESUME) {
-                       /*
-                        * Only disable idle poll if we have forced that
-                        * in a previous call.
-                        */
-                       cpu_idle_poll_ctrl(false);
-               }
-               break;
-       default:
-               BUG();
+               cpu_idle_poll_ctrl(false);
        }
+       return 0;
+}
+
+static int comparator_set_oneshot(struct clock_event_device *evdev)
+{
+       pr_debug("%s: %s\n", __func__, evdev->name);
+
+       disable_cpu_idle_poll = true;
+       /*
+        * If we're using the COUNT and COMPARE registers we
+        * need to force idle poll.
+        */
+       cpu_idle_poll_ctrl(true);
+
+       return 0;
 }
 
 static struct clock_event_device comparator = {
-       .name           = "avr32_comparator",
-       .features       = CLOCK_EVT_FEAT_ONESHOT,
-       .shift          = 16,
-       .rating         = 50,
-       .set_next_event = comparator_next_event,
-       .set_mode       = comparator_mode,
+       .name                   = "avr32_comparator",
+       .features               = CLOCK_EVT_FEAT_ONESHOT,
+       .shift                  = 16,
+       .rating                 = 50,
+       .set_next_event         = comparator_next_event,
+       .set_state_shutdown     = comparator_shutdown,
+       .set_state_oneshot      = comparator_set_oneshot,
+       .tick_resume            = comparator_set_oneshot,
 };
 
 void read_persistent_clock(struct timespec *ts)
index 23b1a97fae7ad686acc581c5888e95d5e4928a1e..52c179bec0cc6c69d4430324a0a581f66e066a6d 100644 (file)
@@ -80,6 +80,9 @@ int clk_enable(struct clk *clk)
 {
        unsigned long flags;
 
+       if (!clk)
+               return 0;
+
        spin_lock_irqsave(&clk_lock, flags);
        __clk_enable(clk);
        spin_unlock_irqrestore(&clk_lock, flags);
@@ -106,6 +109,9 @@ void clk_disable(struct clk *clk)
 {
        unsigned long flags;
 
+       if (IS_ERR_OR_NULL(clk))
+               return;
+
        spin_lock_irqsave(&clk_lock, flags);
        __clk_disable(clk);
        spin_unlock_irqrestore(&clk_lock, flags);
@@ -117,6 +123,9 @@ unsigned long clk_get_rate(struct clk *clk)
        unsigned long flags;
        unsigned long rate;
 
+       if (!clk)
+               return 0;
+
        spin_lock_irqsave(&clk_lock, flags);
        rate = clk->get_rate(clk);
        spin_unlock_irqrestore(&clk_lock, flags);
@@ -129,6 +138,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
 {
        unsigned long flags, actual_rate;
 
+       if (!clk)
+               return 0;
+
        if (!clk->set_rate)
                return -ENOSYS;
 
@@ -145,6 +157,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        unsigned long flags;
        long ret;
 
+       if (!clk)
+               return 0;
+
        if (!clk->set_rate)
                return -ENOSYS;
 
@@ -161,6 +176,9 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
        unsigned long flags;
        int ret;
 
+       if (!clk)
+               return 0;
+
        if (!clk->set_parent)
                return -ENOSYS;
 
@@ -174,7 +192,7 @@ EXPORT_SYMBOL(clk_set_parent);
 
 struct clk *clk_get_parent(struct clk *clk)
 {
-       return clk->parent;
+       return !clk ? NULL : clk->parent;
 }
 EXPORT_SYMBOL(clk_get_parent);
 
index 0c3f25ee3381d9fad606ea36bb09682d362a87d8..f8de767ce2bcc763979ef6e08d4ef4f862a89efb 100644 (file)
@@ -174,6 +174,11 @@ static inline void _writel(unsigned long l, unsigned long addr)
 #define iowrite16 writew
 #define iowrite32 writel
 
+#define ioread16be(addr)       be16_to_cpu(readw(addr))
+#define ioread32be(addr)       be32_to_cpu(readl(addr))
+#define iowrite16be(v, addr)   writew(cpu_to_be16(v), (addr))
+#define iowrite32be(v, addr)   writel(cpu_to_be32(v), (addr))
+
 #define mmiowb()
 
 #define flush_write_buffers() do { } while (0)  /* M32R_FIXME */
index cee5f93e5712f3120d36847dc02d74709bc21929..199a8357838cb24bde2ce5ed5dec7db62feb8d2e 100644 (file)
@@ -151,7 +151,6 @@ config BMIPS_GENERIC
        select BCM7120_L2_IRQ
        select BRCMSTB_L2_IRQ
        select IRQ_MIPS_CPU
-       select RAW_IRQ_ACCESSORS
        select DMA_NONCOHERENT
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
index 01a644f174dd08e34843ca501035b077d777bea2..1ba21204ebe021ee164a9f8f4828dd3f3c836f84 100644 (file)
@@ -190,6 +190,7 @@ int get_c0_perfcount_int(void)
 {
        return ATH79_MISC_IRQ(5);
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index 56f5d080ef9d6cb698ba70cf7027783167000284..b7fa9ae28c3659dbf457aecd7cd17255cd34f5da 100644 (file)
@@ -42,7 +42,7 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
        cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
 
        if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
diff --git a/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h b/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h
deleted file mode 100644 (file)
index 11d3b57..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __ASM_MACH_BCM63XX_DMA_COHERENCE_H
-#define __ASM_MACH_BCM63XX_DMA_COHERENCE_H
-
-#include <asm/bmips.h>
-
-#define plat_post_dma_flush    bmips_post_dma_flush
-
-#include <asm/mach-generic/dma-coherence.h>
-
-#endif /* __ASM_MACH_BCM63XX_DMA_COHERENCE_H */
index 9d810675814291d14ce004f9d4447678af2227c3..ae85694752644339af22557a5ae424cde8271400 100644 (file)
@@ -182,8 +182,39 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
                 * Make sure the buddy is global too (if it's !none,
                 * it better already be global)
                 */
+#ifdef CONFIG_SMP
+               /*
+                * For SMP, multiple CPUs can race, so we need to do
+                * this atomically.
+                */
+#ifdef CONFIG_64BIT
+#define LL_INSN "lld"
+#define SC_INSN "scd"
+#else /* CONFIG_32BIT */
+#define LL_INSN "ll"
+#define SC_INSN "sc"
+#endif
+               unsigned long page_global = _PAGE_GLOBAL;
+               unsigned long tmp;
+
+               __asm__ __volatile__ (
+                       "       .set    push\n"
+                       "       .set    noreorder\n"
+                       "1:     " LL_INSN "     %[tmp], %[buddy]\n"
+                       "       bnez    %[tmp], 2f\n"
+                       "        or     %[tmp], %[tmp], %[global]\n"
+                       "       " SC_INSN "     %[tmp], %[buddy]\n"
+                       "       beqz    %[tmp], 1b\n"
+                       "        nop\n"
+                       "2:\n"
+                       "       .set pop"
+                       : [buddy] "+m" (buddy->pte),
+                         [tmp] "=&r" (tmp)
+                       : [global] "r" (page_global));
+#else /* !CONFIG_SMP */
                if (pte_none(*buddy))
                        pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;
+#endif /* CONFIG_SMP */
        }
 #endif
 }
index 16f1ea9ab191234ee8dc5599803b91dcc2ccf745..03722d4326a1aad05935b58805ec8d881703201e 100644 (file)
@@ -83,8 +83,6 @@ static inline void __cpu_die(unsigned int cpu)
 extern void play_dead(void);
 #endif
 
-extern asmlinkage void smp_call_function_interrupt(void);
-
 static inline void arch_send_call_function_single_ipi(int cpu)
 {
        extern struct plat_smp_ops *mp_ops;     /* private */
index 28d6d9364bd1f2c431df08c72f58262e5297ec5c..a71da576883c8f4b1a3d60279ebfaefb95798031 100644 (file)
                .set    noreorder
                bltz    k0, 8f
                 move   k1, sp
+#ifdef CONFIG_EVA
+               /*
+                * Flush interAptiv's Return Prediction Stack (RPS) by writing
+                * EntryHi. Toggling Config7.RPS is slower and less portable.
+                *
+                * The RPS isn't automatically flushed when exceptions are
+                * taken, which can result in kernel mode speculative accesses
+                * to user addresses if the RPS mispredicts. That's harmless
+                * when user and kernel share the same address space, but with
+                * EVA the same user segments may be unmapped to kernel mode,
+                * even containing sensitive MMIO regions or invalid memory.
+                *
+                * This can happen when the kernel sets the return address to
+                * ret_from_* and jr's to the exception handler, which looks
+                * more like a tail call than a function call. If nested calls
+                * don't evict the last user address in the RPS, it will
+                * mispredict the return and fetch from a user controlled
+                * address into the icache.
+                *
+                * More recent EVA-capable cores with MAAR to restrict
+                * speculative accesses aren't affected.
+                */
+               MFC0    k0, CP0_ENTRYHI
+               MTC0    k0, CP0_ENTRYHI
+#endif
                .set    reorder
                /* Called from user mode, new stack. */
                get_saved_sp
index 3e4491aa6d6b2425865e1d1a3a909cf05aaa4e28..789d7bf4fef3203b3038a9ddaf20c5f70f1bc948 100644 (file)
@@ -154,7 +154,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
                                      unsigned long __user *user_mask_ptr)
 {
        unsigned int real_len;
-       cpumask_t mask;
+       cpumask_t allowed, mask;
        int retval;
        struct task_struct *p;
 
@@ -173,7 +173,8 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
        if (retval)
                goto out_unlock;
 
-       cpumask_and(&mask, &p->thread.user_cpus_allowed, cpu_possible_mask);
+       cpumask_or(&allowed, &p->thread.user_cpus_allowed, &p->cpus_allowed);
+       cpumask_and(&mask, &allowed, cpu_active_mask);
 
 out_unlock:
        read_unlock(&tasklist_lock);
index b130033838ba0c391ef4f9f0c7aa19e5a50b6eb7..5fcec3032f38f6aebdf668af3318997e4f53921f 100644 (file)
@@ -38,7 +38,7 @@ char *mips_get_machine_name(void)
        return mips_machine_name;
 }
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_USE_OF
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
        return add_memory_region(base, size, BOOT_MEM_RAM);
index 74bab9ddd0e1984c9d4e4e95c038bb1d269b60dd..c6bbf21650515d1e71eead45b41a7729f8794476 100644 (file)
@@ -24,7 +24,7 @@ LEAF(relocate_new_kernel)
 
 process_entry:
        PTR_L           s2, (s0)
-       PTR_ADD         s0, s0, SZREG
+       PTR_ADDIU       s0, s0, SZREG
 
        /*
         * In case of a kdump/crash kernel, the indirection page is not
@@ -61,9 +61,9 @@ copy_word:
        /* copy page word by word */
        REG_L           s5, (s2)
        REG_S           s5, (s4)
-       PTR_ADD         s4, s4, SZREG
-       PTR_ADD         s2, s2, SZREG
-       LONG_SUB        s6, s6, 1
+       PTR_ADDIU       s4, s4, SZREG
+       PTR_ADDIU       s2, s2, SZREG
+       LONG_ADDIU      s6, s6, -1
        beq             s6, zero, process_entry
        b               copy_word
        b               process_entry
index ad4d44635c7601162ca0dd8f1b626df28eeeafb2..a6f6b762c47a4c5a2d395e13a1d564964595abe1 100644 (file)
@@ -80,7 +80,7 @@ syscall_trace_entry:
        SAVE_STATIC
        move    s0, t2
        move    a0, sp
-       daddiu  a1, v0, __NR_64_Linux
+       move    a1, v0
        jal     syscall_trace_enter
 
        bltz    v0, 2f                  # seccomp failed? Skip syscall
index 446cc654da56c5f5fcaad749242dd98d593776e1..4b2010654c463158b7dee80194de736195c04595 100644 (file)
@@ -72,7 +72,7 @@ n32_syscall_trace_entry:
        SAVE_STATIC
        move    s0, t2
        move    a0, sp
-       daddiu  a1, v0, __NR_N32_Linux
+       move    a1, v0
        jal     syscall_trace_enter
 
        bltz    v0, 2f                  # seccomp failed? Skip syscall
index 19a7705f2a015ef4b38e1cd0a16eb22c2a2d3ca3..5d7f2634996fd4920f0a4c94e00cd42fae5934b1 100644 (file)
@@ -409,8 +409,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
 
 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 {
-       memset(to, 0, sizeof *to);
-
        if (copy_from_user(to, from, 3*sizeof(int)) ||
            copy_from_user(to->_sifields._pad,
                           from->_sifields._pad, SI_PAD_SIZE32))
index 336708ae5c5b4c74b75416058feabb4bef5e30b1..78cf8c2f1de0e8790923d25ab6e42a85e53a6fe9 100644 (file)
@@ -284,7 +284,7 @@ static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id)
        if (action == 0)
                scheduler_ipi();
        else
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
@@ -336,7 +336,7 @@ static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
        if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index d0744cc77ea7f7a02d94c96faf190787f7e88f64..a31896c33716d424bb30397c17b29af07c6728bb 100644 (file)
@@ -192,16 +192,6 @@ asmlinkage void start_secondary(void)
        cpu_startup_entry(CPUHP_ONLINE);
 }
 
-/*
- * Call into both interrupt handlers, as we share the IPI for them
- */
-void __irq_entry smp_call_function_interrupt(void)
-{
-       irq_enter();
-       generic_smp_call_function_interrupt();
-       irq_exit();
-}
-
 static void stop_this_cpu(void *dummy)
 {
        /*
index e207a43b5f8f0bcbf0544e5289cfc08126cbc7f5..8ea28e6ab37dead56439dc37871b6b18e8ec02d5 100644 (file)
@@ -192,6 +192,7 @@ static void show_stacktrace(struct task_struct *task,
 void show_stack(struct task_struct *task, unsigned long *sp)
 {
        struct pt_regs regs;
+       mm_segment_t old_fs = get_fs();
        if (sp) {
                regs.regs[29] = (unsigned long)sp;
                regs.regs[31] = 0;
@@ -210,7 +211,13 @@ void show_stack(struct task_struct *task, unsigned long *sp)
                        prepare_frametrace(&regs);
                }
        }
+       /*
+        * show_stack() deals exclusively with kernel mode, so be sure to access
+        * the stack in the kernel (not user) address space.
+        */
+       set_fs(KERNEL_DS);
        show_stacktrace(task, &regs);
+       set_fs(old_fs);
 }
 
 static void show_code(unsigned int __user *pc)
@@ -1519,6 +1526,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
        const int field = 2 * sizeof(unsigned long);
        int multi_match = regs->cp0_status & ST0_TS;
        enum ctx_state prev_state;
+       mm_segment_t old_fs = get_fs();
 
        prev_state = exception_enter();
        show_regs(regs);
@@ -1540,8 +1548,13 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
                dump_tlb_all();
        }
 
+       if (!user_mode(regs))
+               set_fs(KERNEL_DS);
+
        show_code((unsigned int __user *) regs->cp0_epc);
 
+       set_fs(old_fs);
+
        /*
         * Some chips may have other causes of machine check (e.g. SB1
         * graduation timer)
index af84bef0c90de4bc65e14669dca132ebb7147846..eb3efd137fd17cdb6e1defa163744a480ad16185 100644 (file)
@@ -438,7 +438,7 @@ do {                                                        \
                : "memory");                                \
 } while(0)
 
-#define     StoreDW(addr, value, res) \
+#define     _StoreDW(addr, value, res) \
 do {                                                        \
                __asm__ __volatile__ (                      \
                        ".set\tpush\n\t"                    \
index 6ab10573490de8a2d5a449e45c3585547c51f7c4..2c218c3bbca57be3d029cdb3320b712092bccd46 100644 (file)
@@ -293,7 +293,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        return IRQ_HANDLED;
 }
 
@@ -466,6 +466,7 @@ int get_c0_perfcount_int(void)
 {
        return ltq_perfcount_irq;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index 509877c6e9d908d7bac6110982c7208ab69204af..1a4738a8f2d3906ccffb58bdf8d9b35ee4b04ef3 100644 (file)
@@ -266,8 +266,11 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 
        if (action & SMP_ASK_C0COUNT) {
                BUG_ON(cpu != 0);
index 77d96db8253c422ac9e48d93e02c6b6f39b41c1b..aab218c36e0d3e2f7669c47343e583e527103169 100644 (file)
@@ -160,18 +160,18 @@ static inline void setup_protection_map(void)
                protection_map[1]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
                protection_map[2]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ);
                protection_map[3]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
-               protection_map[4]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+               protection_map[4]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
                protection_map[5]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
-               protection_map[6]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+               protection_map[6]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
                protection_map[7]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
 
                protection_map[8]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ);
                protection_map[9]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
                protection_map[10] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE | _PAGE_NO_READ);
                protection_map[11] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE);
-               protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+               protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
                protection_map[13] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
-               protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE  | _PAGE_NO_READ);
+               protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE);
                protection_map[15] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE);
 
        } else {
index 36c0f26fac6b0780318958a59fc2665a444a10ea..852a41c6da4507080d611dce0b1fc206caf30556 100644 (file)
@@ -133,7 +133,8 @@ good_area:
 #endif
                                goto bad_area;
                        }
-                       if (!(vma->vm_flags & VM_READ)) {
+                       if (!(vma->vm_flags & VM_READ) &&
+                           exception_epc(regs) != address) {
 #if 0
                                pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] RI violation\n",
                                          raw_smp_processor_id(),
index d1392f8f5811f65ec72445026ac12c4fe15fe6b1..fa8f591f371361ba6fe3654617e6f44690a48a25 100644 (file)
@@ -222,7 +222,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index 5625b190edc061afbf2a8885e976b48014270325..b7bf721eabf5411bfb2f55b6b7d2cdc9ba887f96 100644 (file)
@@ -154,6 +154,7 @@ int get_c0_perfcount_int(void)
 
        return mips_cpu_perf_irq;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
@@ -171,14 +172,17 @@ unsigned int get_c0_compare_int(void)
 
 static void __init init_rtc(void)
 {
-       /* stop the clock whilst setting it up */
-       CMOS_WRITE(RTC_SET | RTC_24H, RTC_CONTROL);
+       unsigned char freq, ctrl;
 
-       /* 32KHz time base */
-       CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
+       /* Set 32KHz time base if not already set */
+       freq = CMOS_READ(RTC_FREQ_SELECT);
+       if ((freq & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ)
+               CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
 
-       /* start the clock */
-       CMOS_WRITE(RTC_24H, RTC_CONTROL);
+       /* Ensure SET bit is clear so RTC can run */
+       ctrl = CMOS_READ(RTC_CONTROL);
+       if (ctrl & RTC_SET)
+               CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL);
 }
 
 void __init plat_time_init(void)
index e1d69895fb1de44f5d8503027f86ebb50f40d5a6..a120b7a5a8fe4e9af03ccb40fc9e7e123f88d633 100644 (file)
@@ -77,6 +77,7 @@ int get_c0_perfcount_int(void)
                return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
        return -1;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index dc3e327fbbac105e71c6b89a039e0f79f91e6f3d..f5fff228b347b6da07d68212fb11f4ae140548c8 100644 (file)
@@ -86,7 +86,7 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc)
 {
        clear_c0_eimr(irq);
        ack_c0_eirr(irq);
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        set_c0_eimr(irq);
 }
 
index 42181c7105df70992892ead68933bcd5375ab74b..f8d3e081b2ebc77e6752dc10a61a69e9a8172b3d 100644 (file)
@@ -114,7 +114,7 @@ static irqreturn_t paravirt_reched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t paravirt_function_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        return IRQ_HANDLED;
 }
 
index 7c73fcb92a108799866c8d603019129d33c57ee6..8a377346f0cabbf5ce91199ca039ec013b16dda1 100644 (file)
@@ -26,6 +26,7 @@ int get_c0_perfcount_int(void)
 {
        return gic_get_c0_perfcount_int();
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 int get_c0_fdc_int(void)
 {
index 10170580a2def4501bb4f149c707d050a900246f..ffa0f7101a9773ec8e24813f37e3c270d912b5e2 100644 (file)
@@ -44,7 +44,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index 53707aacc0f86cb13134546de07ccaf71d76321d..8c624a8b9ea29f5611abceb531de09c865e46b7c 100644 (file)
@@ -89,6 +89,7 @@ int get_c0_perfcount_int(void)
 {
        return rt_perfcount_irq;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index 3fbaef97a1b8d31791e8999bd222e3e1b01c3701..16ec4e12daa3fb7bed3355a5cd56cdb3c87946fc 100644 (file)
@@ -107,10 +107,14 @@ static void ip27_do_irq_mask0(void)
                scheduler_ipi();
        } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ);
-               smp_call_function_interrupt();
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
        } else if (pend0 & (1UL << CPU_CALL_B_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ);
-               smp_call_function_interrupt();
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
        } else
 #endif
        {
index af7d44edd9a8f118b79944ecf21310634f308b56..4c71aea2566372c3f3af8627c79e91fb9aede4ea 100644 (file)
@@ -29,8 +29,6 @@
 #include <asm/sibyte/bcm1480_regs.h>
 #include <asm/sibyte/bcm1480_int.h>
 
-extern void smp_call_function_interrupt(void);
-
 /*
  * These are routines for dealing with the bcm1480 smp capabilities
  * independent of board/firmware
@@ -184,6 +182,9 @@ void bcm1480_mailbox_interrupt(void)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 }
index c0c4b3f88a086f2c331cce0b311d9c547d3b5a6a..1cf66f5ff23d1a5afca26ffd9bc638566d8f68cb 100644 (file)
@@ -172,6 +172,9 @@ void sb1250_mailbox_interrupt(void)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 }
index d3a831ac0f927e17304d55c406c60029ad55a4e0..da50e0c9c57e69af8779f0df979231104704ab6e 100644 (file)
@@ -966,8 +966,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s)
 
 int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
 {
-       memset(to, 0, sizeof *to);
-
        if (copy_from_user(to, from, 3*sizeof(int)) ||
            copy_from_user(to->_sifields._pad,
                           from->_sifields._pad, SI_PAD_SIZE32))
index 5cf5e6ea213baaeee1b6e017636eae95aba6b0c6..7cf0df859d0536bcfd4752d4b581da810873196b 100644 (file)
@@ -1478,7 +1478,7 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
        }
 
        /* Unmask the event */
-       if (eeh_enabled())
+       if (ret == EEH_NEXT_ERR_NONE && eeh_enabled())
                enable_irq(eeh_event_irq);
 
        return ret;
index 5738d315248b202b4a26aff084b07e819a80855c..85cbc96eff6cbd60e3e6bb9bf126091181eb5ef1 100644 (file)
@@ -2220,7 +2220,7 @@ static void pnv_pci_ioda_setup_opal_tce_kill(struct pnv_phb *phb)
 
 static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned shift,
                unsigned levels, unsigned long limit,
-               unsigned long *current_offset)
+               unsigned long *current_offset, unsigned long *total_allocated)
 {
        struct page *tce_mem = NULL;
        __be64 *addr, *tmp;
@@ -2236,6 +2236,7 @@ static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned shift,
        }
        addr = page_address(tce_mem);
        memset(addr, 0, allocated);
+       *total_allocated += allocated;
 
        --levels;
        if (!levels) {
@@ -2245,7 +2246,7 @@ static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned shift,
 
        for (i = 0; i < entries; ++i) {
                tmp = pnv_pci_ioda2_table_do_alloc_pages(nid, shift,
-                               levels, limit, current_offset);
+                               levels, limit, current_offset, total_allocated);
                if (!tmp)
                        break;
 
@@ -2267,7 +2268,7 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
                struct iommu_table *tbl)
 {
        void *addr;
-       unsigned long offset = 0, level_shift;
+       unsigned long offset = 0, level_shift, total_allocated = 0;
        const unsigned window_shift = ilog2(window_size);
        unsigned entries_shift = window_shift - page_shift;
        unsigned table_shift = max_t(unsigned, entries_shift + 3, PAGE_SHIFT);
@@ -2286,7 +2287,7 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
 
        /* Allocate TCE table */
        addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift,
-                       levels, tce_table_size, &offset);
+                       levels, tce_table_size, &offset, &total_allocated);
 
        /* addr==NULL means that the first level allocation failed */
        if (!addr)
@@ -2308,7 +2309,7 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
                        page_shift);
        tbl->it_level_size = 1ULL << (level_shift - 3);
        tbl->it_indirect_levels = levels - 1;
-       tbl->it_allocated_size = offset;
+       tbl->it_allocated_size = total_allocated;
 
        pr_devel("Created TCE table: ws=%08llx ts=%lx @%08llx\n",
                        window_size, tce_table_size, bus_offset);
index c7d1b9d0901147ba359fa03e2e4e026699413fa2..a2da259d932741614c4f6b78642c491b3829b223 100644 (file)
 
 int main(void)
 {
-       DEFINE(__THREAD_info, offsetof(struct task_struct, stack));
-       DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp));
-       DEFINE(__THREAD_mm_segment, offsetof(struct task_struct, thread.mm_segment));
-       BLANK();
+       DEFINE(__TASK_thread_info, offsetof(struct task_struct, stack));
+       DEFINE(__TASK_thread, offsetof(struct task_struct, thread));
        DEFINE(__TASK_pid, offsetof(struct task_struct, pid));
        BLANK();
-       DEFINE(__THREAD_per_cause, offsetof(struct task_struct, thread.per_event.cause));
-       DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address));
-       DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid));
+       DEFINE(__THREAD_ksp, offsetof(struct thread_struct, ksp));
+       DEFINE(__THREAD_per_cause, offsetof(struct thread_struct, per_event.cause));
+       DEFINE(__THREAD_per_address, offsetof(struct thread_struct, per_event.address));
+       DEFINE(__THREAD_per_paid, offsetof(struct thread_struct, per_event.paid));
+       DEFINE(__THREAD_trap_tdb, offsetof(struct thread_struct, trap_tdb));
        BLANK();
        DEFINE(__TI_task, offsetof(struct thread_info, task));
        DEFINE(__TI_flags, offsetof(struct thread_info, flags));
@@ -176,7 +176,6 @@ int main(void)
        DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));
        DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap));
        DEFINE(__LC_PGM_TDB, offsetof(struct _lowcore, pgm_tdb));
-       DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));
        DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce));
        DEFINE(__SIE_PROG0C, offsetof(struct kvm_s390_sie_block, prog0c));
        DEFINE(__SIE_PROG20, offsetof(struct kvm_s390_sie_block, prog20));
index bff5e3b6d8223b8f9a9c84d8f99235d3d4e648bc..8ba32436effe4b9da0a271ae1ec0ad2a2bd689e7 100644 (file)
@@ -138,6 +138,8 @@ int init_cache_level(unsigned int cpu)
        union cache_topology ct;
        enum cache_type ctype;
 
+       if (!test_facility(34))
+               return -EOPNOTSUPP;
        if (!this_cpu_ci)
                return -EINVAL;
        ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
index 3238893c9d4ff66d492ce2a04421b85fa0cc0c34..84062e7a77dad75c50fa60822255ee2b20b34181 100644 (file)
@@ -178,17 +178,21 @@ _PIF_WORK = (_PIF_PER_TRAP)
  */
 ENTRY(__switch_to)
        stmg    %r6,%r15,__SF_GPRS(%r15)        # store gprs of prev task
-       stg     %r15,__THREAD_ksp(%r2)          # store kernel stack of prev
-       lg      %r4,__THREAD_info(%r2)          # get thread_info of prev
-       lg      %r5,__THREAD_info(%r3)          # get thread_info of next
+       lgr     %r1,%r2
+       aghi    %r1,__TASK_thread               # thread_struct of prev task
+       lg      %r4,__TASK_thread_info(%r2)     # get thread_info of prev
+       lg      %r5,__TASK_thread_info(%r3)     # get thread_info of next
+       stg     %r15,__THREAD_ksp(%r1)          # store kernel stack of prev
+       lgr     %r1,%r3
+       aghi    %r1,__TASK_thread               # thread_struct of next task
        lgr     %r15,%r5
        aghi    %r15,STACK_INIT                 # end of kernel stack of next
        stg     %r3,__LC_CURRENT                # store task struct of next
        stg     %r5,__LC_THREAD_INFO            # store thread info of next
        stg     %r15,__LC_KERNEL_STACK          # store end of kernel stack
+       lg      %r15,__THREAD_ksp(%r1)          # load kernel stack of next
        lctl    %c4,%c4,__TASK_pid(%r3)         # load pid to control reg. 4
        mvc     __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
-       lg      %r15,__THREAD_ksp(%r3)          # load kernel stack of next
        lmg     %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        br      %r14
 
@@ -417,6 +421,7 @@ ENTRY(pgm_check_handler)
        LAST_BREAK %r14
        lg      %r15,__LC_KERNEL_STACK
        lg      %r14,__TI_task(%r12)
+       aghi    %r14,__TASK_thread      # pointer to thread_struct
        lghi    %r13,__LC_PGM_TDB
        tm      __LC_PGM_ILC+2,0x02     # check for transaction abort
        jz      2f
index 4d96c9f5345538471cea4cd62620439c88a7f867..7bea81d8a3635025b0f372c3f908ade71b188e1b 100644 (file)
@@ -259,7 +259,7 @@ void vector_exception(struct pt_regs *regs)
        }
 
        /* get vector interrupt code from fpc */
-       asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
+       asm volatile("stfpc %0" : "=Q" (current->thread.fp_regs.fpc));
        vic = (current->thread.fp_regs.fpc & 0xf00) >> 8;
        switch (vic) {
        case 1: /* invalid vector operation */
@@ -297,7 +297,7 @@ void data_exception(struct pt_regs *regs)
 
        location = get_trap_ip(regs);
 
-       asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
+       asm volatile("stfpc %0" : "=Q" (current->thread.fp_regs.fpc));
        /* Check for vector register enablement */
        if (MACHINE_HAS_VX && !current->thread.vxrs &&
            (current->thread.fp_regs.fpc & FPC_DXC_MASK) == 0xfe00) {
index 2078f92d15ac90adcfec617b46df750e073b76d0..f32f843a3631359e49b88169ab8a1eed2b76b946 100644 (file)
@@ -1742,10 +1742,10 @@ static bool ibs_enabled(struct kvm_vcpu *vcpu)
 
 static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
 {
-       if (!vcpu->requests)
-               return 0;
 retry:
        kvm_s390_vcpu_request_handled(vcpu);
+       if (!vcpu->requests)
+               return 0;
        /*
         * We use MMU_RELOAD just to re-arm the ipte notifier for the
         * guest prefix page. gmap_ipte_notify will wait on the ptl lock.
index fee782acc2ee51f6a3aae4b28152ec76981c8350..8d2e5165865f2c27b50fe8b1c6845de45666698a 100644 (file)
@@ -448,13 +448,13 @@ static void bpf_jit_prologue(struct bpf_jit *jit)
                EMIT6_DISP_LH(0xe3000000, 0x0004, REG_SKB_DATA, REG_0,
                              BPF_REG_1, offsetof(struct sk_buff, data));
        }
-       /* BPF compatibility: clear A (%b7) and X (%b8) registers */
-       if (REG_SEEN(BPF_REG_7))
-               /* lghi %b7,0 */
-               EMIT4_IMM(0xa7090000, BPF_REG_7, 0);
-       if (REG_SEEN(BPF_REG_8))
-               /* lghi %b8,0 */
-               EMIT4_IMM(0xa7090000, BPF_REG_8, 0);
+       /* BPF compatibility: clear A (%b0) and X (%b7) registers */
+       if (REG_SEEN(BPF_REG_A))
+               /* lghi %ba,0 */
+               EMIT4_IMM(0xa7090000, BPF_REG_A, 0);
+       if (REG_SEEN(BPF_REG_X))
+               /* lghi %bx,0 */
+               EMIT4_IMM(0xa7090000, BPF_REG_X, 0);
 }
 
 /*
index 1f0aa2024e94be341efc079f58145a2e70909052..6424249d5f785e698c4283677c1b975668393478 100644 (file)
  * Must preserve %o5 between VISEntryHalf and VISExitHalf */
 
 #define VISEntryHalf                                   \
-       rd              %fprs, %o5;                     \
-       andcc           %o5, FPRS_FEF, %g0;             \
-       be,pt           %icc, 297f;                     \
-        sethi          %hi(298f), %g7;                 \
-       sethi           %hi(VISenterhalf), %g1;         \
-       jmpl            %g1 + %lo(VISenterhalf), %g0;   \
-        or             %g7, %lo(298f), %g7;            \
-       clr             %o5;                            \
-297:   wr              %o5, FPRS_FEF, %fprs;           \
-298:
+       VISEntry
+
+#define VISExitHalf                                    \
+       VISExit
 
 #define VISEntryHalfFast(fail_label)                   \
        rd              %fprs, %o5;                     \
@@ -47,7 +41,7 @@
        ba,a,pt         %xcc, fail_label;               \
 297:   wr              %o5, FPRS_FEF, %fprs;
 
-#define VISExitHalf                                    \
+#define VISExitHalfFast                                        \
        wr              %o5, 0, %fprs;
 
 #ifndef __ASSEMBLY__
index 140527a20e7df03cc0a0dd9e6a3438f44b432177..83aeeb1dffdb3b4c29293d5924cd5259e2269ce5 100644 (file)
@@ -240,8 +240,11 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
        add             %o0, 0x40, %o0
        bne,pt          %icc, 1b
         LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
+#ifdef NON_USER_COPY
+       VISExitHalfFast
+#else
        VISExitHalf
-
+#endif
        brz,pn          %o2, .Lexit
         cmp            %o2, 19
        ble,pn          %icc, .Lsmall_unaligned
index b320ae9e2e2e8b27c7184f58ddc640b4adf6fdda..a063d84336d6384a03d7ddd8a5143f0909801ed8 100644 (file)
@@ -44,9 +44,8 @@ vis1: ldub            [%g6 + TI_FPSAVED], %g3
 
         stx            %g3, [%g6 + TI_GSR]
 2:     add             %g6, %g1, %g3
-       cmp             %o5, FPRS_DU
-       be,pn           %icc, 6f
-        sll            %g1, 3, %g1
+       mov             FPRS_DU | FPRS_DL | FPRS_FEF, %o5
+       sll             %g1, 3, %g1
        stb             %o5, [%g3 + TI_FPSAVED]
        rd              %gsr, %g2
        add             %g6, %g1, %g3
@@ -80,65 +79,3 @@ vis1:        ldub            [%g6 + TI_FPSAVED], %g3
        .align          32
 80:    jmpl            %g7 + %g0, %g0
         nop
-
-6:     ldub            [%g3 + TI_FPSAVED], %o5
-       or              %o5, FPRS_DU, %o5
-       add             %g6, TI_FPREGS+0x80, %g2
-       stb             %o5, [%g3 + TI_FPSAVED]
-
-       sll             %g1, 5, %g1
-       add             %g6, TI_FPREGS+0xc0, %g3
-       wr              %g0, FPRS_FEF, %fprs
-       membar          #Sync
-       stda            %f32, [%g2 + %g1] ASI_BLK_P
-       stda            %f48, [%g3 + %g1] ASI_BLK_P
-       membar          #Sync
-       ba,pt           %xcc, 80f
-        nop
-
-       .align          32
-80:    jmpl            %g7 + %g0, %g0
-        nop
-
-       .align          32
-VISenterhalf:
-       ldub            [%g6 + TI_FPDEPTH], %g1
-       brnz,a,pn       %g1, 1f
-        cmp            %g1, 1
-       stb             %g0, [%g6 + TI_FPSAVED]
-       stx             %fsr, [%g6 + TI_XFSR]
-       clr             %o5
-       jmpl            %g7 + %g0, %g0
-        wr             %g0, FPRS_FEF, %fprs
-
-1:     bne,pn          %icc, 2f
-        srl            %g1, 1, %g1
-       ba,pt           %xcc, vis1
-        sub            %g7, 8, %g7
-2:     addcc           %g6, %g1, %g3
-       sll             %g1, 3, %g1
-       andn            %o5, FPRS_DU, %g2
-       stb             %g2, [%g3 + TI_FPSAVED]
-
-       rd              %gsr, %g2
-       add             %g6, %g1, %g3
-       stx             %g2, [%g3 + TI_GSR]
-       add             %g6, %g1, %g2
-       stx             %fsr, [%g2 + TI_XFSR]
-       sll             %g1, 5, %g1
-3:     andcc           %o5, FPRS_DL, %g0
-       be,pn           %icc, 4f
-        add            %g6, TI_FPREGS, %g2
-
-       add             %g6, TI_FPREGS+0x40, %g3
-       membar          #Sync
-       stda            %f0, [%g2 + %g1] ASI_BLK_P
-       stda            %f16, [%g3 + %g1] ASI_BLK_P
-       membar          #Sync
-       ba,pt           %xcc, 4f
-        nop
-
-       .align          32
-4:     and             %o5, FPRS_DU, %o5
-       jmpl            %g7 + %g0, %g0
-        wr             %o5, FPRS_FEF, %fprs
index 1d649a95660c8cad57fbe90feadb7c43b9e8263f..8069ce12f20b13d514160cec8db0c0d88b64b27e 100644 (file)
@@ -135,10 +135,6 @@ EXPORT_SYMBOL(copy_user_page);
 void VISenter(void);
 EXPORT_SYMBOL(VISenter);
 
-/* CRYPTO code needs this */
-void VISenterhalf(void);
-EXPORT_SYMBOL(VISenterhalf);
-
 extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *);
 extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *,
                unsigned long *);
index e8c2c04143cda81db9b51018a449b611263ab68d..c667e104a0c251d73f02ce2b812ed09878ca79a0 100644 (file)
@@ -113,8 +113,6 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
        if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
                return -EFAULT;
 
-       memset(to, 0, sizeof(*to));
-
        err = __get_user(to->si_signo, &from->si_signo);
        err |= __get_user(to->si_errno, &from->si_errno);
        err |= __get_user(to->si_code, &from->si_code);
index 99c9ff87e0187502179f8012afa5bd54309d2eb9..6b755d125783f45b05de02e3fe5f7b5e32d1af45 100644 (file)
@@ -1139,7 +1139,7 @@ static void __init load_hv_initrd(void)
 
 void __init free_initrd_mem(unsigned long begin, unsigned long end)
 {
-       free_bootmem(__pa(begin), end - begin);
+       free_bootmem_late(__pa(begin), end - begin);
 }
 
 static int __init setup_initrd(char *str)
index 2c82bd150d43546d03d01de07ecc8e43f5a459d8..7d69afd8b6fa47dab5478ce4c8d831ae6780881a 100644 (file)
@@ -1193,6 +1193,10 @@ static efi_status_t setup_e820(struct boot_params *params,
                unsigned int e820_type = 0;
                unsigned long m = efi->efi_memmap;
 
+#ifdef CONFIG_X86_64
+               m |= (u64)efi->efi_memmap_hi << 32;
+#endif
+
                d = (efi_memory_desc_t *)(m + (i * efi->efi_memdesc_size));
                switch (d->type) {
                case EFI_RESERVED_TYPE:
index bb187a6a877cc62666afb43421eb7e5e8b6fbbfe..a7e257d9cb90b9f34ecb03180fec8c54f2afd82f 100644 (file)
@@ -140,6 +140,7 @@ sysexit_from_sys_call:
         */
        andl    $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
        movl    RIP(%rsp), %ecx         /* User %eip */
+       movq    RAX(%rsp), %rax
        RESTORE_RSI_RDI
        xorl    %edx, %edx              /* Do not leak kernel information */
        xorq    %r8, %r8
@@ -205,7 +206,6 @@ sysexit_from_sys_call:
        movl    RDX(%rsp), %edx         /* arg3 */
        movl    RSI(%rsp), %ecx         /* arg4 */
        movl    RDI(%rsp), %r8d         /* arg5 */
-       movl    %ebp, %r9d              /* arg6 */
        .endm
 
        .macro auditsys_exit exit
@@ -220,7 +220,6 @@ sysexit_from_sys_call:
 1:     setbe   %al                     /* 1 if error, 0 if not */
        movzbl  %al, %edi               /* zero-extend that into %edi */
        call    __audit_syscall_exit
-       movq    RAX(%rsp), %rax         /* reload syscall return value */
        movl    $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %edi
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
@@ -236,6 +235,7 @@ sysexit_from_sys_call:
 
 sysenter_auditsys:
        auditsys_entry_common
+       movl    %ebp, %r9d              /* reload 6th syscall arg */
        jmp     sysenter_dispatch
 
 sysexit_audit:
@@ -336,7 +336,7 @@ ENTRY(entry_SYSCALL_compat)
         * 32-bit zero extended:
         */
        ASM_STAC
-1:     movl    (%r8), %ebp
+1:     movl    (%r8), %r9d
        _ASM_EXTABLE(1b, ia32_badarg)
        ASM_CLAC
        orl     $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
@@ -346,7 +346,7 @@ ENTRY(entry_SYSCALL_compat)
 cstar_do_call:
        /* 32-bit syscall -> 64-bit C ABI argument conversion */
        movl    %edi, %r8d              /* arg5 */
-       movl    %ebp, %r9d              /* arg6 */
+       /* r9 already loaded */         /* arg6 */
        xchg    %ecx, %esi              /* rsi:arg2, rcx:arg4 */
        movl    %ebx, %edi              /* arg1 */
        movl    %edx, %edx              /* arg3 (zero extension) */
@@ -358,7 +358,6 @@ cstar_dispatch:
        call    *ia32_sys_call_table(, %rax, 8)
        movq    %rax, RAX(%rsp)
 1:
-       movl    RCX(%rsp), %ebp
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
        testl   $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
@@ -369,6 +368,7 @@ sysretl_from_sys_call:
        RESTORE_RSI_RDI_RDX
        movl    RIP(%rsp), %ecx
        movl    EFLAGS(%rsp), %r11d
+       movq    RAX(%rsp), %rax
        xorq    %r10, %r10
        xorq    %r9, %r9
        xorq    %r8, %r8
@@ -392,7 +392,9 @@ sysretl_from_sys_call:
 
 #ifdef CONFIG_AUDITSYSCALL
 cstar_auditsys:
+       movl    %r9d, R9(%rsp)          /* register to be clobbered by call */
        auditsys_entry_common
+       movl    R9(%rsp), %r9d          /* reload 6th syscall arg */
        jmp     cstar_dispatch
 
 sysretl_audit:
@@ -404,14 +406,16 @@ cstar_tracesys:
        testl   $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
        jz      cstar_auditsys
 #endif
+       xchgl   %r9d, %ebp
        SAVE_EXTRA_REGS
        xorl    %eax, %eax              /* Do not leak kernel information */
        movq    %rax, R11(%rsp)
        movq    %rax, R10(%rsp)
-       movq    %rax, R9(%rsp)
+       movq    %r9, R9(%rsp)
        movq    %rax, R8(%rsp)
        movq    %rsp, %rdi              /* &pt_regs -> arg1 */
        call    syscall_trace_enter
+       movl    R9(%rsp), %r9d
 
        /* Reload arg registers from stack. (see sysenter_tracesys) */
        movl    RCX(%rsp), %ecx
@@ -421,6 +425,7 @@ cstar_tracesys:
        movl    %eax, %eax              /* zero extension */
 
        RESTORE_EXTRA_REGS
+       xchgl   %ebp, %r9d
        jmp     cstar_do_call
 END(entry_SYSCALL_compat)
 
index a0bf89fd26470102f6f38031808437f01afe8e1f..4e10d73cf01844edc201ed23f51d28a72a537521 100644 (file)
@@ -280,21 +280,6 @@ static inline void clear_LDT(void)
        set_ldt(NULL, 0);
 }
 
-/*
- * load one particular LDT into the current CPU
- */
-static inline void load_LDT_nolock(mm_context_t *pc)
-{
-       set_ldt(pc->ldt, pc->size);
-}
-
-static inline void load_LDT(mm_context_t *pc)
-{
-       preempt_disable();
-       load_LDT_nolock(pc);
-       preempt_enable();
-}
-
 static inline unsigned long get_desc_base(const struct desc_struct *desc)
 {
        return (unsigned)(desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24));
index 09b9620a73b4841893fc2bd01bfd614d43e7e214..364d27481a52a34f5031933ecc577af0ebf3c129 100644 (file)
@@ -9,8 +9,7 @@
  * we put the segment information here.
  */
 typedef struct {
-       void *ldt;
-       int size;
+       struct ldt_struct *ldt;
 
 #ifdef CONFIG_X86_64
        /* True if mm supports a task running in 32 bit compatibility mode. */
index 804a3a6030ca046500e7a092cfa0a854be77796f..984abfe47edc85db7b1a1809d5e0b2d22a7c0449 100644 (file)
@@ -33,6 +33,50 @@ static inline void load_mm_cr4(struct mm_struct *mm)
 static inline void load_mm_cr4(struct mm_struct *mm) {}
 #endif
 
+/*
+ * ldt_structs can be allocated, used, and freed, but they are never
+ * modified while live.
+ */
+struct ldt_struct {
+       /*
+        * Xen requires page-aligned LDTs with special permissions.  This is
+        * needed to prevent us from installing evil descriptors such as
+        * call gates.  On native, we could merge the ldt_struct and LDT
+        * allocations, but it's not worth trying to optimize.
+        */
+       struct desc_struct *entries;
+       int size;
+};
+
+static inline void load_mm_ldt(struct mm_struct *mm)
+{
+       struct ldt_struct *ldt;
+
+       /* lockless_dereference synchronizes with smp_store_release */
+       ldt = lockless_dereference(mm->context.ldt);
+
+       /*
+        * Any change to mm->context.ldt is followed by an IPI to all
+        * CPUs with the mm active.  The LDT will not be freed until
+        * after the IPI is handled by all such CPUs.  This means that,
+        * if the ldt_struct changes before we return, the values we see
+        * will be safe, and the new values will be loaded before we run
+        * any user code.
+        *
+        * NB: don't try to convert this to use RCU without extreme care.
+        * We would still need IRQs off, because we don't want to change
+        * the local LDT after an IPI loaded a newer value than the one
+        * that we can see.
+        */
+
+       if (unlikely(ldt))
+               set_ldt(ldt->entries, ldt->size);
+       else
+               clear_LDT();
+
+       DEBUG_LOCKS_WARN_ON(preemptible());
+}
+
 /*
  * Used for LDT copy/destruction.
  */
@@ -78,12 +122,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                 * was called and then modify_ldt changed
                 * prev->context.ldt but suppressed an IPI to this CPU.
                 * In this case, prev->context.ldt != NULL, because we
-                * never free an LDT while the mm still exists.  That
-                * means that next->context.ldt != prev->context.ldt,
-                * because mms never share an LDT.
+                * never set context.ldt to NULL while the mm still
+                * exists.  That means that next->context.ldt !=
+                * prev->context.ldt, because mms never share an LDT.
                 */
                if (unlikely(prev->context.ldt != next->context.ldt))
-                       load_LDT_nolock(&next->context);
+                       load_mm_ldt(next);
        }
 #ifdef CONFIG_SMP
          else {
@@ -106,7 +150,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                        load_cr3(next->pgd);
                        trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
                        load_mm_cr4(next);
-                       load_LDT_nolock(&next->context);
+                       load_mm_ldt(next);
                }
        }
 #endif
index 6fe6b182c9981dd891a9a5bc9a55b3e6591a6f9f..9dfce4e0417d92adc623d32ff93f67109316b451 100644 (file)
@@ -57,9 +57,9 @@ struct sigcontext {
        unsigned long ip;
        unsigned long flags;
        unsigned short cs;
-       unsigned short __pad2;  /* Was called gs, but was always zero. */
-       unsigned short __pad1;  /* Was called fs, but was always zero. */
-       unsigned short ss;
+       unsigned short gs;
+       unsigned short fs;
+       unsigned short __pad0;
        unsigned long err;
        unsigned long trapno;
        unsigned long oldmask;
index a4ae82eb82aa8485146aee83376ba26fb9306afe..cd54147cb365fb3622121c782eee8e7fb3ddcc77 100644 (file)
@@ -354,7 +354,7 @@ struct kvm_xcrs {
 struct kvm_sync_regs {
 };
 
-#define KVM_QUIRK_LINT0_REENABLED      (1 << 0)
-#define KVM_QUIRK_CD_NW_CLEARED                (1 << 1)
+#define KVM_X86_QUIRK_LINT0_REENABLED  (1 << 0)
+#define KVM_X86_QUIRK_CD_NW_CLEARED    (1 << 1)
 
 #endif /* _ASM_X86_KVM_H */
index 0e8a973de9ee8aec0c555a5e9e8b23348e2cc10b..40836a9a7250c99a16dc5969057177f66aa57186 100644 (file)
@@ -177,24 +177,9 @@ struct sigcontext {
        __u64 rip;
        __u64 eflags;           /* RFLAGS */
        __u16 cs;
-
-       /*
-        * Prior to 2.5.64 ("[PATCH] x86-64 updates for 2.5.64-bk3"),
-        * Linux saved and restored fs and gs in these slots.  This
-        * was counterproductive, as fsbase and gsbase were never
-        * saved, so arch_prctl was presumably unreliable.
-        *
-        * If these slots are ever needed for any other purpose, there
-        * is some risk that very old 64-bit binaries could get
-        * confused.  I doubt that many such binaries still work,
-        * though, since the same patch in 2.5.64 also removed the
-        * 64-bit set_thread_area syscall, so it appears that there is
-        * no TLS API that works in both pre- and post-2.5.64 kernels.
-        */
-       __u16 __pad2;           /* Was gs. */
-       __u16 __pad1;           /* Was fs. */
-
-       __u16 ss;
+       __u16 gs;
+       __u16 fs;
+       __u16 __pad0;
        __u64 err;
        __u64 trapno;
        __u64 oldmask;
index 845dc0df2002472275a39e421502cdb0768c54a1..206052e5551702258a8c65f308fefaed2c988a07 100644 (file)
@@ -943,7 +943,7 @@ static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info)
         */
        if (irq < nr_legacy_irqs() && data->count == 1) {
                if (info->ioapic_trigger != data->trigger)
-                       mp_register_handler(irq, data->trigger);
+                       mp_register_handler(irq, info->ioapic_trigger);
                data->entry.trigger = data->trigger = info->ioapic_trigger;
                data->entry.polarity = data->polarity = info->ioapic_polarity;
        }
index 922c5e0cea4c961b1aa6e7a266ce588de7f7a300..cb9e5df42dd2464f7249eea78cc28753eb858ec0 100644 (file)
@@ -1410,7 +1410,7 @@ void cpu_init(void)
        load_sp0(t, &current->thread);
        set_tss_desc(cpu, t);
        load_TR_desc();
-       load_LDT(&init_mm.context);
+       load_mm_ldt(&init_mm);
 
        clear_all_debug_regs();
        dbg_restore_debug_regs();
@@ -1459,7 +1459,7 @@ void cpu_init(void)
        load_sp0(t, thread);
        set_tss_desc(cpu, t);
        load_TR_desc();
-       load_LDT(&init_mm.context);
+       load_mm_ldt(&init_mm);
 
        t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
 
index 3658de47900f9a921a0f8373db962e061d42db3a..9469dfa556074db4dff41212a4873b31d5907772 100644 (file)
@@ -2179,21 +2179,25 @@ static unsigned long get_segment_base(unsigned int segment)
        int idx = segment >> 3;
 
        if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) {
+               struct ldt_struct *ldt;
+
                if (idx > LDT_ENTRIES)
                        return 0;
 
-               if (idx > current->active_mm->context.size)
+               /* IRQs are off, so this synchronizes with smp_store_release */
+               ldt = lockless_dereference(current->active_mm->context.ldt);
+               if (!ldt || idx > ldt->size)
                        return 0;
 
-               desc = current->active_mm->context.ldt;
+               desc = &ldt->entries[idx];
        } else {
                if (idx > GDT_ENTRIES)
                        return 0;
 
-               desc = raw_cpu_ptr(gdt_page.gdt);
+               desc = raw_cpu_ptr(gdt_page.gdt) + idx;
        }
 
-       return get_desc_base(desc + idx);
+       return get_desc_base(desc);
 }
 
 #ifdef CONFIG_COMPAT
index b9826a981fb20fa45a7c1255e277e9ad1cd5d150..6326ae24e4d5b4f3d228111c10f5c85df0e40d3f 100644 (file)
@@ -2534,7 +2534,7 @@ static int intel_pmu_cpu_prepare(int cpu)
        if (x86_pmu.extra_regs || x86_pmu.lbr_sel_map) {
                cpuc->shared_regs = allocate_shared_regs(cpu);
                if (!cpuc->shared_regs)
-                       return NOTIFY_BAD;
+                       goto err;
        }
 
        if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) {
@@ -2542,18 +2542,27 @@ static int intel_pmu_cpu_prepare(int cpu)
 
                cpuc->constraint_list = kzalloc(sz, GFP_KERNEL);
                if (!cpuc->constraint_list)
-                       return NOTIFY_BAD;
+                       goto err_shared_regs;
 
                cpuc->excl_cntrs = allocate_excl_cntrs(cpu);
-               if (!cpuc->excl_cntrs) {
-                       kfree(cpuc->constraint_list);
-                       kfree(cpuc->shared_regs);
-                       return NOTIFY_BAD;
-               }
+               if (!cpuc->excl_cntrs)
+                       goto err_constraint_list;
+
                cpuc->excl_thread_id = 0;
        }
 
        return NOTIFY_OK;
+
+err_constraint_list:
+       kfree(cpuc->constraint_list);
+       cpuc->constraint_list = NULL;
+
+err_shared_regs:
+       kfree(cpuc->shared_regs);
+       cpuc->shared_regs = NULL;
+
+err:
+       return NOTIFY_BAD;
 }
 
 static void intel_pmu_cpu_starting(int cpu)
index 188076161c1be51afe135d6289b8ce0e96952bf3..377e8f8ed39186ad4ef57b33264592ed8459a037 100644 (file)
@@ -951,6 +951,14 @@ static u64 intel_cqm_event_count(struct perf_event *event)
        if (!cqm_group_leader(event))
                return 0;
 
+       /*
+        * Getting up-to-date values requires an SMP IPI which is not
+        * possible if we're being called in interrupt context. Return
+        * the cached values instead.
+        */
+       if (unlikely(in_interrupt()))
+               goto out;
+
        /*
         * Notice that we don't perform the reading of an RMID
         * atomically, because we can't hold a spin lock across the
@@ -1247,7 +1255,7 @@ static inline void cqm_pick_event_reader(int cpu)
        cpumask_set_cpu(cpu, &cqm_cpumask);
 }
 
-static void intel_cqm_cpu_prepare(unsigned int cpu)
+static void intel_cqm_cpu_starting(unsigned int cpu)
 {
        struct intel_pqr_state *state = &per_cpu(pqr_state, cpu);
        struct cpuinfo_x86 *c = &cpu_data(cpu);
@@ -1288,13 +1296,11 @@ static int intel_cqm_cpu_notifier(struct notifier_block *nb,
        unsigned int cpu  = (unsigned long)hcpu;
 
        switch (action & ~CPU_TASKS_FROZEN) {
-       case CPU_UP_PREPARE:
-               intel_cqm_cpu_prepare(cpu);
-               break;
        case CPU_DOWN_PREPARE:
                intel_cqm_cpu_exit(cpu);
                break;
        case CPU_STARTING:
+               intel_cqm_cpu_starting(cpu);
                cqm_pick_event_reader(cpu);
                break;
        }
@@ -1365,7 +1371,7 @@ static int __init intel_cqm_init(void)
                goto out;
 
        for_each_online_cpu(i) {
-               intel_cqm_cpu_prepare(i);
+               intel_cqm_cpu_starting(i);
                cqm_pick_event_reader(i);
        }
 
index 0b39173dd9714ebed0eaca58b27af65e86dfbc0c..1e173f6285c73b76b2e6ab41daed7681406c5d15 100644 (file)
@@ -351,9 +351,15 @@ static int __init x86_noxsave_setup(char *s)
 
        setup_clear_cpu_cap(X86_FEATURE_XSAVE);
        setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
+       setup_clear_cpu_cap(X86_FEATURE_XSAVEC);
        setup_clear_cpu_cap(X86_FEATURE_XSAVES);
        setup_clear_cpu_cap(X86_FEATURE_AVX);
        setup_clear_cpu_cap(X86_FEATURE_AVX2);
+       setup_clear_cpu_cap(X86_FEATURE_AVX512F);
+       setup_clear_cpu_cap(X86_FEATURE_AVX512PF);
+       setup_clear_cpu_cap(X86_FEATURE_AVX512ER);
+       setup_clear_cpu_cap(X86_FEATURE_AVX512CD);
+       setup_clear_cpu_cap(X86_FEATURE_MPX);
 
        return 1;
 }
index c37886d759ccac2736c36b357cc0f399786f2fb3..2bcc0525f1c10e80b3db33df075b3189c4a68239 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/uaccess.h>
 
 #include <asm/mmu_context.h>
 #include <asm/syscalls.h>
 
-#ifdef CONFIG_SMP
+/* context.lock is held for us, so we don't need any locking. */
 static void flush_ldt(void *current_mm)
 {
-       if (current->active_mm == current_mm)
-               load_LDT(&current->active_mm->context);
+       mm_context_t *pc;
+
+       if (current->active_mm != current_mm)
+               return;
+
+       pc = &current->active_mm->context;
+       set_ldt(pc->ldt->entries, pc->ldt->size);
 }
-#endif
 
-static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
+/* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */
+static struct ldt_struct *alloc_ldt_struct(int size)
 {
-       void *oldldt, *newldt;
-       int oldsize;
-
-       if (mincount <= pc->size)
-               return 0;
-       oldsize = pc->size;
-       mincount = (mincount + (PAGE_SIZE / LDT_ENTRY_SIZE - 1)) &
-                       (~(PAGE_SIZE / LDT_ENTRY_SIZE - 1));
-       if (mincount * LDT_ENTRY_SIZE > PAGE_SIZE)
-               newldt = vmalloc(mincount * LDT_ENTRY_SIZE);
+       struct ldt_struct *new_ldt;
+       int alloc_size;
+
+       if (size > LDT_ENTRIES)
+               return NULL;
+
+       new_ldt = kmalloc(sizeof(struct ldt_struct), GFP_KERNEL);
+       if (!new_ldt)
+               return NULL;
+
+       BUILD_BUG_ON(LDT_ENTRY_SIZE != sizeof(struct desc_struct));
+       alloc_size = size * LDT_ENTRY_SIZE;
+
+       /*
+        * Xen is very picky: it requires a page-aligned LDT that has no
+        * trailing nonzero bytes in any page that contains LDT descriptors.
+        * Keep it simple: zero the whole allocation and never allocate less
+        * than PAGE_SIZE.
+        */
+       if (alloc_size > PAGE_SIZE)
+               new_ldt->entries = vzalloc(alloc_size);
        else
-               newldt = (void *)__get_free_page(GFP_KERNEL);
-
-       if (!newldt)
-               return -ENOMEM;
+               new_ldt->entries = kzalloc(PAGE_SIZE, GFP_KERNEL);
 
-       if (oldsize)
-               memcpy(newldt, pc->ldt, oldsize * LDT_ENTRY_SIZE);
-       oldldt = pc->ldt;
-       memset(newldt + oldsize * LDT_ENTRY_SIZE, 0,
-              (mincount - oldsize) * LDT_ENTRY_SIZE);
+       if (!new_ldt->entries) {
+               kfree(new_ldt);
+               return NULL;
+       }
 
-       paravirt_alloc_ldt(newldt, mincount);
+       new_ldt->size = size;
+       return new_ldt;
+}
 
-#ifdef CONFIG_X86_64
-       /* CHECKME: Do we really need this ? */
-       wmb();
-#endif
-       pc->ldt = newldt;
-       wmb();
-       pc->size = mincount;
-       wmb();
-
-       if (reload) {
-#ifdef CONFIG_SMP
-               preempt_disable();
-               load_LDT(pc);
-               if (!cpumask_equal(mm_cpumask(current->mm),
-                                  cpumask_of(smp_processor_id())))
-                       smp_call_function(flush_ldt, current->mm, 1);
-               preempt_enable();
-#else
-               load_LDT(pc);
-#endif
-       }
-       if (oldsize) {
-               paravirt_free_ldt(oldldt, oldsize);
-               if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE)
-                       vfree(oldldt);
-               else
-                       put_page(virt_to_page(oldldt));
-       }
-       return 0;
+/* After calling this, the LDT is immutable. */
+static void finalize_ldt_struct(struct ldt_struct *ldt)
+{
+       paravirt_alloc_ldt(ldt->entries, ldt->size);
 }
 
-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
+/* context.lock is held */
+static void install_ldt(struct mm_struct *current_mm,
+                       struct ldt_struct *ldt)
 {
-       int err = alloc_ldt(new, old->size, 0);
-       int i;
+       /* Synchronizes with lockless_dereference in load_mm_ldt. */
+       smp_store_release(&current_mm->context.ldt, ldt);
+
+       /* Activate the LDT for all CPUs using current_mm. */
+       on_each_cpu_mask(mm_cpumask(current_mm), flush_ldt, current_mm, true);
+}
 
-       if (err < 0)
-               return err;
+static void free_ldt_struct(struct ldt_struct *ldt)
+{
+       if (likely(!ldt))
+               return;
 
-       for (i = 0; i < old->size; i++)
-               write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE);
-       return 0;
+       paravirt_free_ldt(ldt->entries, ldt->size);
+       if (ldt->size * LDT_ENTRY_SIZE > PAGE_SIZE)
+               vfree(ldt->entries);
+       else
+               kfree(ldt->entries);
+       kfree(ldt);
 }
 
 /*
@@ -104,17 +105,37 @@ static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
  */
 int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
+       struct ldt_struct *new_ldt;
        struct mm_struct *old_mm;
        int retval = 0;
 
        mutex_init(&mm->context.lock);
-       mm->context.size = 0;
        old_mm = current->mm;
-       if (old_mm && old_mm->context.size > 0) {
-               mutex_lock(&old_mm->context.lock);
-               retval = copy_ldt(&mm->context, &old_mm->context);
-               mutex_unlock(&old_mm->context.lock);
+       if (!old_mm) {
+               mm->context.ldt = NULL;
+               return 0;
        }
+
+       mutex_lock(&old_mm->context.lock);
+       if (!old_mm->context.ldt) {
+               mm->context.ldt = NULL;
+               goto out_unlock;
+       }
+
+       new_ldt = alloc_ldt_struct(old_mm->context.ldt->size);
+       if (!new_ldt) {
+               retval = -ENOMEM;
+               goto out_unlock;
+       }
+
+       memcpy(new_ldt->entries, old_mm->context.ldt->entries,
+              new_ldt->size * LDT_ENTRY_SIZE);
+       finalize_ldt_struct(new_ldt);
+
+       mm->context.ldt = new_ldt;
+
+out_unlock:
+       mutex_unlock(&old_mm->context.lock);
        return retval;
 }
 
@@ -125,53 +146,47 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
  */
 void destroy_context(struct mm_struct *mm)
 {
-       if (mm->context.size) {
-#ifdef CONFIG_X86_32
-               /* CHECKME: Can this ever happen ? */
-               if (mm == current->active_mm)
-                       clear_LDT();
-#endif
-               paravirt_free_ldt(mm->context.ldt, mm->context.size);
-               if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE)
-                       vfree(mm->context.ldt);
-               else
-                       put_page(virt_to_page(mm->context.ldt));
-               mm->context.size = 0;
-       }
+       free_ldt_struct(mm->context.ldt);
+       mm->context.ldt = NULL;
 }
 
 static int read_ldt(void __user *ptr, unsigned long bytecount)
 {
-       int err;
+       int retval;
        unsigned long size;
        struct mm_struct *mm = current->mm;
 
-       if (!mm->context.size)
-               return 0;
+       mutex_lock(&mm->context.lock);
+
+       if (!mm->context.ldt) {
+               retval = 0;
+               goto out_unlock;
+       }
+
        if (bytecount > LDT_ENTRY_SIZE * LDT_ENTRIES)
                bytecount = LDT_ENTRY_SIZE * LDT_ENTRIES;
 
-       mutex_lock(&mm->context.lock);
-       size = mm->context.size * LDT_ENTRY_SIZE;
+       size = mm->context.ldt->size * LDT_ENTRY_SIZE;
        if (size > bytecount)
                size = bytecount;
 
-       err = 0;
-       if (copy_to_user(ptr, mm->context.ldt, size))
-               err = -EFAULT;
-       mutex_unlock(&mm->context.lock);
-       if (err < 0)
-               goto error_return;
+       if (copy_to_user(ptr, mm->context.ldt->entries, size)) {
+               retval = -EFAULT;
+               goto out_unlock;
+       }
+
        if (size != bytecount) {
-               /* zero-fill the rest */
-               if (clear_user(ptr + size, bytecount - size) != 0) {
-                       err = -EFAULT;
-                       goto error_return;
+               /* Zero-fill the rest and pretend we read bytecount bytes. */
+               if (clear_user(ptr + size, bytecount - size)) {
+                       retval = -EFAULT;
+                       goto out_unlock;
                }
        }
-       return bytecount;
-error_return:
-       return err;
+       retval = bytecount;
+
+out_unlock:
+       mutex_unlock(&mm->context.lock);
+       return retval;
 }
 
 static int read_default_ldt(void __user *ptr, unsigned long bytecount)
@@ -195,6 +210,8 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
        struct desc_struct ldt;
        int error;
        struct user_desc ldt_info;
+       int oldsize, newsize;
+       struct ldt_struct *new_ldt, *old_ldt;
 
        error = -EINVAL;
        if (bytecount != sizeof(ldt_info))
@@ -213,34 +230,39 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
                        goto out;
        }
 
-       mutex_lock(&mm->context.lock);
-       if (ldt_info.entry_number >= mm->context.size) {
-               error = alloc_ldt(&current->mm->context,
-                                 ldt_info.entry_number + 1, 1);
-               if (error < 0)
-                       goto out_unlock;
-       }
-
-       /* Allow LDTs to be cleared by the user. */
-       if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
-               if (oldmode || LDT_empty(&ldt_info)) {
-                       memset(&ldt, 0, sizeof(ldt));
-                       goto install;
+       if ((oldmode && !ldt_info.base_addr && !ldt_info.limit) ||
+           LDT_empty(&ldt_info)) {
+               /* The user wants to clear the entry. */
+               memset(&ldt, 0, sizeof(ldt));
+       } else {
+               if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) {
+                       error = -EINVAL;
+                       goto out;
                }
+
+               fill_ldt(&ldt, &ldt_info);
+               if (oldmode)
+                       ldt.avl = 0;
        }
 
-       if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) {
-               error = -EINVAL;
+       mutex_lock(&mm->context.lock);
+
+       old_ldt = mm->context.ldt;
+       oldsize = old_ldt ? old_ldt->size : 0;
+       newsize = max((int)(ldt_info.entry_number + 1), oldsize);
+
+       error = -ENOMEM;
+       new_ldt = alloc_ldt_struct(newsize);
+       if (!new_ldt)
                goto out_unlock;
-       }
 
-       fill_ldt(&ldt, &ldt_info);
-       if (oldmode)
-               ldt.avl = 0;
+       if (old_ldt)
+               memcpy(new_ldt->entries, old_ldt->entries, oldsize * LDT_ENTRY_SIZE);
+       new_ldt->entries[ldt_info.entry_number] = ldt;
+       finalize_ldt_struct(new_ldt);
 
-       /* Install the new entry ...  */
-install:
-       write_ldt_entry(mm->context.ldt, ldt_info.entry_number, &ldt);
+       install_ldt(mm, new_ldt);
+       free_ldt_struct(old_ldt);
        error = 0;
 
 out_unlock:
index 71d7849a07f7ca93b126bf081464012c7a91c9a6..f6b916387590158706b8ef4ec68bfef64702ff0f 100644 (file)
@@ -121,11 +121,11 @@ void __show_regs(struct pt_regs *regs, int all)
 void release_thread(struct task_struct *dead_task)
 {
        if (dead_task->mm) {
-               if (dead_task->mm->context.size) {
+               if (dead_task->mm->context.ldt) {
                        pr_warn("WARNING: dead process %s still has LDT? <%p/%d>\n",
                                dead_task->comm,
                                dead_task->mm->context.ldt,
-                               dead_task->mm->context.size);
+                               dead_task->mm->context.ldt->size);
                        BUG();
                }
        }
index 206996c1669db344aba7ff072f734552723e7938..71820c42b6ce6bc1020bbc44277967d7e23f011e 100644 (file)
@@ -93,8 +93,15 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
                COPY(r15);
 #endif /* CONFIG_X86_64 */
 
+#ifdef CONFIG_X86_32
                COPY_SEG_CPL3(cs);
                COPY_SEG_CPL3(ss);
+#else /* !CONFIG_X86_32 */
+               /* Kernel saves and restores only the CS segment register on signals,
+                * which is the bare minimum needed to allow mixed 32/64-bit code.
+                * App's signal handler can save/restore other segments if needed. */
+               COPY_SEG_CPL3(cs);
+#endif /* CONFIG_X86_32 */
 
                get_user_ex(tmpflags, &sc->flags);
                regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
@@ -154,9 +161,8 @@ int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
 #else /* !CONFIG_X86_32 */
                put_user_ex(regs->flags, &sc->flags);
                put_user_ex(regs->cs, &sc->cs);
-               put_user_ex(0, &sc->__pad2);
-               put_user_ex(0, &sc->__pad1);
-               put_user_ex(regs->ss, &sc->ss);
+               put_user_ex(0, &sc->gs);
+               put_user_ex(0, &sc->fs);
 #endif /* CONFIG_X86_32 */
 
                put_user_ex(fpstate, &sc->fpstate);
@@ -451,19 +457,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
 
        regs->sp = (unsigned long)frame;
 
-       /*
-        * Set up the CS and SS registers to run signal handlers in
-        * 64-bit mode, even if the handler happens to be interrupting
-        * 32-bit or 16-bit code.
-        *
-        * SS is subtle.  In 64-bit mode, we don't need any particular
-        * SS descriptor, but we do need SS to be valid.  It's possible
-        * that the old SS is entirely bogus -- this can happen if the
-        * signal we're trying to deliver is #GP or #SS caused by a bad
-        * SS value.
-        */
+       /* Set up the CS register to run signal handlers in 64-bit mode,
+          even if the handler happens to be interrupting 32-bit code. */
        regs->cs = __USER_CS;
-       regs->ss = __USER_DS;
 
        return 0;
 }
index 9b4d51d0c0d013274f7ba46c2e58319f0d1d9145..0ccb53a9fcd9361b83c7acd26e1f64601816a3d1 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/mm.h>
 #include <linux/ptrace.h>
 #include <asm/desc.h>
+#include <asm/mmu_context.h>
 
 unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs)
 {
@@ -27,13 +28,14 @@ unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *re
                struct desc_struct *desc;
                unsigned long base;
 
-               seg &= ~7UL;
+               seg >>= 3;
 
                mutex_lock(&child->mm->context.lock);
-               if (unlikely((seg >> 3) >= child->mm->context.size))
+               if (unlikely(!child->mm->context.ldt ||
+                            seg >= child->mm->context.ldt->size))
                        addr = -1L; /* bogus selector, access would fault */
                else {
-                       desc = child->mm->context.ldt + seg;
+                       desc = &child->mm->context.ldt->entries[seg];
                        base = get_desc_base(desc);
 
                        /* 16-bit code segment? */
index 954e98a8c2e38bf9861d4d6349eb721264e8cb18..2a5ca97c263bb48092ea80f88c7d30120ea63b6e 100644 (file)
@@ -1595,7 +1595,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
        for (i = 0; i < APIC_LVT_NUM; i++)
                apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
        apic_update_lvtt(apic);
-       if (!(vcpu->kvm->arch.disabled_quirks & KVM_QUIRK_LINT0_REENABLED))
+       if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_LINT0_REENABLED))
                apic_set_reg(apic, APIC_LVT0,
                             SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
        apic_manage_nmi_watchdog(apic, kvm_apic_get_reg(apic, APIC_LVT0));
index de1d2d8062e24048232af909d684f0c2ed9e21bc..9e8bf13572e6dc3f95d33d24f079d63e256a3a7a 100644 (file)
@@ -120,6 +120,16 @@ static u8 mtrr_default_type(struct kvm_mtrr *mtrr_state)
        return mtrr_state->deftype & IA32_MTRR_DEF_TYPE_TYPE_MASK;
 }
 
+static u8 mtrr_disabled_type(void)
+{
+       /*
+        * Intel SDM 11.11.2.2: all MTRRs are disabled when
+        * IA32_MTRR_DEF_TYPE.E bit is cleared, and the UC
+        * memory type is applied to all of physical memory.
+        */
+       return MTRR_TYPE_UNCACHABLE;
+}
+
 /*
 * Three terms are used in the following code:
 * - segment, it indicates the address segments covered by fixed MTRRs.
@@ -434,6 +444,8 @@ struct mtrr_iter {
 
        /* output fields. */
        int mem_type;
+       /* mtrr is completely disabled? */
+       bool mtrr_disabled;
        /* [start, end) is not fully covered in MTRRs? */
        bool partial_map;
 
@@ -549,7 +561,7 @@ static void mtrr_lookup_var_next(struct mtrr_iter *iter)
 static void mtrr_lookup_start(struct mtrr_iter *iter)
 {
        if (!mtrr_is_enabled(iter->mtrr_state)) {
-               iter->partial_map = true;
+               iter->mtrr_disabled = true;
                return;
        }
 
@@ -563,6 +575,7 @@ static void mtrr_lookup_init(struct mtrr_iter *iter,
        iter->mtrr_state = mtrr_state;
        iter->start = start;
        iter->end = end;
+       iter->mtrr_disabled = false;
        iter->partial_map = false;
        iter->fixed = false;
        iter->range = NULL;
@@ -656,15 +669,19 @@ u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
                return MTRR_TYPE_WRBACK;
        }
 
-       /* It is not covered by MTRRs. */
-       if (iter.partial_map) {
-               /*
-                * We just check one page, partially covered by MTRRs is
-                * impossible.
-                */
-               WARN_ON(type != -1);
-               type = mtrr_default_type(mtrr_state);
-       }
+       if (iter.mtrr_disabled)
+               return mtrr_disabled_type();
+
+       /* not contained in any MTRRs. */
+       if (type == -1)
+               return mtrr_default_type(mtrr_state);
+
+       /*
+        * We just check one page, partially covered by MTRRs is
+        * impossible.
+        */
+       WARN_ON(iter.partial_map);
+
        return type;
 }
 EXPORT_SYMBOL_GPL(kvm_mtrr_get_guest_memory_type);
@@ -689,6 +706,9 @@ bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
                        return false;
        }
 
+       if (iter.mtrr_disabled)
+               return true;
+
        if (!iter.partial_map)
                return true;
 
index bbc678a66b18719287b091787db96cf1f9f98981..8e0c0844c6b9681e31e64bdeba0f1822108bec3e 100644 (file)
@@ -1672,7 +1672,7 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
         * does not do it - this results in some delay at
         * reboot
         */
-       if (!(vcpu->kvm->arch.disabled_quirks & KVM_QUIRK_CD_NW_CLEARED))
+       if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_CD_NW_CLEARED))
                cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
        svm->vmcb->save.cr0 = cr0;
        mark_dirty(svm->vmcb, VMCB_CR);
index 5b4e9384717a17257ea20ef47031dd5f158273a2..83b7b5cd75d52dd67976274da3c11807f1c35490 100644 (file)
@@ -8650,7 +8650,10 @@ static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
 
        if (kvm_read_cr0(vcpu) & X86_CR0_CD) {
                ipat = VMX_EPT_IPAT_BIT;
-               cache = MTRR_TYPE_UNCACHABLE;
+               if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_CD_NW_CLEARED))
+                       cache = MTRR_TYPE_WRBACK;
+               else
+                       cache = MTRR_TYPE_UNCACHABLE;
                goto exit;
        }
 
index 5ef2560075bfb80e6fdabcdf51f71258091e4339..8f0f6eca69da1dc6db95c16782871580bf57091d 100644 (file)
@@ -2105,7 +2105,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                if (guest_cpuid_has_tsc_adjust(vcpu)) {
                        if (!msr_info->host_initiated) {
                                s64 adj = data - vcpu->arch.ia32_tsc_adjust_msr;
-                               kvm_x86_ops->adjust_tsc_offset(vcpu, adj, true);
+                               adjust_tsc_offset_guest(vcpu, adj);
                        }
                        vcpu->arch.ia32_tsc_adjust_msr = data;
                }
@@ -6327,6 +6327,7 @@ static void process_smi_save_state_64(struct kvm_vcpu *vcpu, char *buf)
 static void process_smi(struct kvm_vcpu *vcpu)
 {
        struct kvm_segment cs, ds;
+       struct desc_ptr dt;
        char buf[512];
        u32 cr0;
 
@@ -6359,6 +6360,10 @@ static void process_smi(struct kvm_vcpu *vcpu)
 
        kvm_x86_ops->set_cr4(vcpu, 0);
 
+       /* Undocumented: IDT limit is set to zero on entry to SMM.  */
+       dt.address = dt.size = 0;
+       kvm_x86_ops->set_idt(vcpu, &dt);
+
        __kvm_set_dr(vcpu, 7, DR7_FIXED_1);
 
        cs.selector = (vcpu->arch.smbase >> 4) & 0xffff;
index edc8cdcd786b00627a1029c8bb3b2aedcb291d09..0ca2f3e4803c2a5846be297a51eb5c1cf67aff4a 100644 (file)
@@ -147,6 +147,11 @@ static inline void kvm_register_writel(struct kvm_vcpu *vcpu,
        return kvm_register_write(vcpu, reg, val);
 }
 
+static inline bool kvm_check_has_quirk(struct kvm *kvm, u64 quirk)
+{
+       return !(kvm->arch.disabled_quirks & quirk);
+}
+
 void kvm_before_handle_nmi(struct kvm_vcpu *vcpu);
 void kvm_after_handle_nmi(struct kvm_vcpu *vcpu);
 void kvm_set_pending_timer(struct kvm_vcpu *vcpu);
index f37e84ab49f38e335bde57880a6cbe8640fb2c4b..3d8f2e421466a8af255eba9602748fee8753a377 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/traps.h>
-#include <asm/desc.h>
 #include <asm/user.h>
 #include <asm/fpu/internal.h>
 
@@ -181,7 +180,7 @@ void math_emulate(struct math_emu_info *info)
                        math_abort(FPU_info, SIGILL);
                }
 
-               code_descriptor = LDT_DESCRIPTOR(FPU_CS);
+               code_descriptor = FPU_get_ldt_descriptor(FPU_CS);
                if (SEG_D_SIZE(code_descriptor)) {
                        /* The above test may be wrong, the book is not clear */
                        /* Segmented 32 bit protected mode */
index 9ccecb61a4fa129a82028b27edc18b91a2f99042..5e044d506b7aae8b17b2142966b11477cfe8e372 100644 (file)
 #include <linux/kernel.h>
 #include <linux/mm.h>
 
-/* s is always from a cpu register, and the cpu does bounds checking
- * during register load --> no further bounds checks needed */
-#define LDT_DESCRIPTOR(s)      (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3])
+#include <asm/desc.h>
+#include <asm/mmu_context.h>
+
+static inline struct desc_struct FPU_get_ldt_descriptor(unsigned seg)
+{
+       static struct desc_struct zero_desc;
+       struct desc_struct ret = zero_desc;
+
+#ifdef CONFIG_MODIFY_LDT_SYSCALL
+       seg >>= 3;
+       mutex_lock(&current->mm->context.lock);
+       if (current->mm->context.ldt && seg < current->mm->context.ldt->size)
+               ret = current->mm->context.ldt->entries[seg];
+       mutex_unlock(&current->mm->context.lock);
+#endif
+       return ret;
+}
+
 #define SEG_D_SIZE(x)          ((x).b & (3 << 21))
 #define SEG_G_BIT(x)           ((x).b & (1 << 23))
 #define SEG_GRANULARITY(x)     (((x).b & (1 << 23)) ? 4096 : 1)
index 6ef5e99380f92134ba86a6a693b5ac6d3434e6d4..8300db71c2a62681006e137350961742190ec9dc 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/stddef.h>
 
 #include <asm/uaccess.h>
-#include <asm/desc.h>
 
 #include "fpu_system.h"
 #include "exception.h"
@@ -158,7 +157,7 @@ static long pm_address(u_char FPU_modrm, u_char segment,
                addr->selector = PM_REG_(segment);
        }
 
-       descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
+       descriptor = FPU_get_ldt_descriptor(addr->selector);
        base_address = SEG_BASE_ADDR(descriptor);
        address = base_address + offset;
        limit = base_address
index cc5ccc415cc01ef8ea9e58b3f81a281c9ab412bf..b9c78f3bcd6739718def393f49d1f1cbb0e8bb5c 100644 (file)
@@ -63,8 +63,6 @@ static int __ioremap_check_ram(unsigned long start_pfn, unsigned long nr_pages,
                    !PageReserved(pfn_to_page(start_pfn + i)))
                        return 1;
 
-       WARN_ONCE(1, "ioremap on RAM pfn 0x%lx\n", start_pfn);
-
        return 0;
 }
 
@@ -94,7 +92,6 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        pgprot_t prot;
        int retval;
        void __iomem *ret_addr;
-       int ram_region;
 
        /* Don't allow wraparound or zero size */
        last_addr = phys_addr + size - 1;
@@ -117,23 +114,15 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        /*
         * Don't allow anybody to remap normal RAM that we're using..
         */
-       /* First check if whole region can be identified as RAM or not */
-       ram_region = region_is_ram(phys_addr, size);
-       if (ram_region > 0) {
-               WARN_ONCE(1, "ioremap on RAM at 0x%lx - 0x%lx\n",
-                               (unsigned long int)phys_addr,
-                               (unsigned long int)last_addr);
+       pfn      = phys_addr >> PAGE_SHIFT;
+       last_pfn = last_addr >> PAGE_SHIFT;
+       if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
+                                         __ioremap_check_ram) == 1) {
+               WARN_ONCE(1, "ioremap on RAM at %pa - %pa\n",
+                         &phys_addr, &last_addr);
                return NULL;
        }
 
-       /* If could not be identified(-1), check page by page */
-       if (ram_region < 0) {
-               pfn      = phys_addr >> PAGE_SHIFT;
-               last_pfn = last_addr >> PAGE_SHIFT;
-               if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
-                                         __ioremap_check_ram) == 1)
-                       return NULL;
-       }
        /*
         * Mappings have to be page-aligned
         */
index 9d518d693b4b7adf07463c695f3cd14412a19192..844b06d67df4da95cec611375d55c05d52884efd 100644 (file)
@@ -126,3 +126,10 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
        }
 }
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+       if (vma->vm_flags & VM_MPX)
+               return "[mpx]";
+       return NULL;
+}
index 7a657f58bbea152057262a61e325c169f78bc516..db1b0bc5017c9f01b456a97b5b84d6d40a2c03b2 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <asm/trace/mpx.h>
 
-static const char *mpx_mapping_name(struct vm_area_struct *vma)
-{
-       return "[mpx]";
-}
-
-static struct vm_operations_struct mpx_vma_ops = {
-       .name = mpx_mapping_name,
-};
-
-static int is_mpx_vma(struct vm_area_struct *vma)
-{
-       return (vma->vm_ops == &mpx_vma_ops);
-}
-
 static inline unsigned long mpx_bd_size_bytes(struct mm_struct *mm)
 {
        if (is_64bit_mm(mm))
@@ -53,9 +39,6 @@ static inline unsigned long mpx_bt_size_bytes(struct mm_struct *mm)
 /*
  * This is really a simplified "vm_mmap". it only handles MPX
  * bounds tables (the bounds directory is user-allocated).
- *
- * Later on, we use the vma->vm_ops to uniquely identify these
- * VMAs.
  */
 static unsigned long mpx_mmap(unsigned long len)
 {
@@ -101,7 +84,6 @@ static unsigned long mpx_mmap(unsigned long len)
                ret = -ENOMEM;
                goto out;
        }
-       vma->vm_ops = &mpx_vma_ops;
 
        if (vm_flags & VM_LOCKED) {
                up_write(&mm->mmap_sem);
@@ -812,7 +794,7 @@ static noinline int zap_bt_entries_mapping(struct mm_struct *mm,
                 * so stop immediately and return an error.  This
                 * probably results in a SIGSEGV.
                 */
-               if (!is_mpx_vma(vma))
+               if (!(vma->vm_flags & VM_MPX))
                        return -EINVAL;
 
                len = min(vma->vm_end, end) - addr;
@@ -945,9 +927,9 @@ static int try_unmap_single_bt(struct mm_struct *mm,
         * lots of tables even though we have no actual table
         * entries in use.
         */
-       while (next && is_mpx_vma(next))
+       while (next && (next->vm_flags & VM_MPX))
                next = next->vm_next;
-       while (prev && is_mpx_vma(prev))
+       while (prev && (prev->vm_flags & VM_MPX))
                prev = prev->vm_prev;
        /*
         * We know 'start' and 'end' lie within an area controlled
index 3250f2371aea5c9f2c8f8f19d4f6535627e0e188..90b924acd9822ffdd9409b9fd97325ea7954b97a 100644 (file)
@@ -117,7 +117,7 @@ static void flush_tlb_func(void *info)
                } else {
                        unsigned long addr;
                        unsigned long nr_pages =
-                               f->flush_end - f->flush_start / PAGE_SIZE;
+                               (f->flush_end - f->flush_start) / PAGE_SIZE;
                        addr = f->flush_start;
                        while (addr < f->flush_end) {
                                __flush_tlb_single(addr);
index 579a8fd74be07804d983a298641b755526f1cb44..be2e7a2b10d7169b39b0849703b305ebb52c8933 100644 (file)
@@ -269,7 +269,7 @@ static void emit_bpf_tail_call(u8 **pprog)
        EMIT4(0x48, 0x8B, 0x46,                   /* mov rax, qword ptr [rsi + 16] */
              offsetof(struct bpf_array, map.max_entries));
        EMIT3(0x48, 0x39, 0xD0);                  /* cmp rax, rdx */
-#define OFFSET1 44 /* number of bytes to jump */
+#define OFFSET1 47 /* number of bytes to jump */
        EMIT2(X86_JBE, OFFSET1);                  /* jbe out */
        label1 = cnt;
 
@@ -278,15 +278,15 @@ static void emit_bpf_tail_call(u8 **pprog)
         */
        EMIT2_off32(0x8B, 0x85, -STACKSIZE + 36); /* mov eax, dword ptr [rbp - 516] */
        EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT);     /* cmp eax, MAX_TAIL_CALL_CNT */
-#define OFFSET2 33
+#define OFFSET2 36
        EMIT2(X86_JA, OFFSET2);                   /* ja out */
        label2 = cnt;
        EMIT3(0x83, 0xC0, 0x01);                  /* add eax, 1 */
        EMIT2_off32(0x89, 0x85, -STACKSIZE + 36); /* mov dword ptr [rbp - 516], eax */
 
        /* prog = array->prog[index]; */
-       EMIT4(0x48, 0x8D, 0x44, 0xD6);            /* lea rax, [rsi + rdx * 8 + 0x50] */
-       EMIT1(offsetof(struct bpf_array, prog));
+       EMIT4_off32(0x48, 0x8D, 0x84, 0xD6,       /* lea rax, [rsi + rdx * 8 + offsetof(...)] */
+                   offsetof(struct bpf_array, prog));
        EMIT3(0x48, 0x8B, 0x00);                  /* mov rax, qword ptr [rax] */
 
        /* if (prog == NULL)
index cfba30f273921b302d03883be593d77d6a3f1fe7..e4308fe6afe81e4d8be5a42a6cc682174761fe1f 100644 (file)
@@ -972,6 +972,11 @@ u64 efi_mem_attributes(unsigned long phys_addr)
 
 static int __init arch_parse_efi_cmdline(char *str)
 {
+       if (!str) {
+               pr_warn("need at least one option\n");
+               return -EINVAL;
+       }
+
        if (parse_option_str(str, "old_map"))
                set_bit(EFI_OLD_MEMMAP, &efi.flags);
        if (parse_option_str(str, "debug"))
index 0d7dd1f5ac36fa6814c18522dd28561566c570eb..9ab52791fed59e3ab2e531611037c4ed9dc7bde3 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/fpu/internal.h>
 #include <asm/debugreg.h>
 #include <asm/cpu.h>
+#include <asm/mmu_context.h>
 
 #ifdef CONFIG_X86_32
 __visible unsigned long saved_context_ebx;
@@ -153,7 +154,7 @@ static void fix_processor_context(void)
        syscall_init();                         /* This sets MSR_*STAR and related */
 #endif
        load_TR_desc();                         /* This does ltr */
-       load_LDT(&current->active_mm->context); /* This does lldt */
+       load_mm_ldt(current->active_mm);        /* This does lldt */
 
        fpu__resume_cpu();
 }
index 7322755f337af760db6086450591c584c4dcda77..4b6e29ac0968c1a76451d3ff773652bc4afed138 100644 (file)
@@ -13,13 +13,13 @@ CFLAGS_mmu.o                        := $(nostackp)
 obj-y          := enlighten.o setup.o multicalls.o mmu.o irq.o \
                        time.o xen-asm.o xen-asm_$(BITS).o \
                        grant-table.o suspend.o platform-pci-unplug.o \
-                       p2m.o
+                       p2m.o apic.o
 
 obj-$(CONFIG_EVENT_TRACING) += trace.o
 
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
 obj-$(CONFIG_XEN_DEBUG_FS)     += debugfs.o
-obj-$(CONFIG_XEN_DOM0)         += apic.o vga.o
+obj-$(CONFIG_XEN_DOM0)         += vga.o
 obj-$(CONFIG_SWIOTLB_XEN)      += pci-swiotlb-xen.o
 obj-$(CONFIG_XEN_EFI)          += efi.o
index 0b95c9b8283fe2afe885d9a8ae98393c14ecc498..11d6fb4e8483d529f833cbc1276ea4ffd3c68102 100644 (file)
@@ -483,6 +483,7 @@ static void set_aliased_prot(void *v, pgprot_t prot)
        pte_t pte;
        unsigned long pfn;
        struct page *page;
+       unsigned char dummy;
 
        ptep = lookup_address((unsigned long)v, &level);
        BUG_ON(ptep == NULL);
@@ -492,6 +493,32 @@ static void set_aliased_prot(void *v, pgprot_t prot)
 
        pte = pfn_pte(pfn, prot);
 
+       /*
+        * Careful: update_va_mapping() will fail if the virtual address
+        * we're poking isn't populated in the page tables.  We don't
+        * need to worry about the direct map (that's always in the page
+        * tables), but we need to be careful about vmap space.  In
+        * particular, the top level page table can lazily propagate
+        * entries between processes, so if we've switched mms since we
+        * vmapped the target in the first place, we might not have the
+        * top-level page table entry populated.
+        *
+        * We disable preemption because we want the same mm active when
+        * we probe the target and when we issue the hypercall.  We'll
+        * have the same nominal mm, but if we're a kernel thread, lazy
+        * mm dropping could change our pgd.
+        *
+        * Out of an abundance of caution, this uses __get_user() to fault
+        * in the target address just in case there's some obscure case
+        * in which the target address isn't readable.
+        */
+
+       preempt_disable();
+
+       pagefault_disable();    /* Avoid warnings due to being atomic. */
+       __get_user(dummy, (unsigned char __user __force *)v);
+       pagefault_enable();
+
        if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0))
                BUG();
 
@@ -503,6 +530,8 @@ static void set_aliased_prot(void *v, pgprot_t prot)
                                BUG();
        } else
                kmap_flush_unused();
+
+       preempt_enable();
 }
 
 static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
@@ -510,6 +539,17 @@ static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
        const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
        int i;
 
+       /*
+        * We need to mark the all aliases of the LDT pages RO.  We
+        * don't need to call vm_flush_aliases(), though, since that's
+        * only responsible for flushing aliases out the TLBs, not the
+        * page tables, and Xen will flush the TLB for us if needed.
+        *
+        * To avoid confusing future readers: none of this is necessary
+        * to load the LDT.  The hypervisor only checks this when the
+        * LDT is faulted in due to subsequent descriptor access.
+        */
+
        for(i = 0; i < entries; i += entries_per_page)
                set_aliased_prot(ldt + i, PAGE_KERNEL_RO);
 }
index c20fe29e65f48b4706789e0ad59bb33b1a3acc18..2292721b1d103844ade9f8a7f436a649c811f77d 100644 (file)
@@ -101,17 +101,15 @@ struct dom0_vga_console_info;
 
 #ifdef CONFIG_XEN_DOM0
 void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size);
-void __init xen_init_apic(void);
 #else
 static inline void __init xen_init_vga(const struct dom0_vga_console_info *info,
                                       size_t size)
 {
 }
-static inline void __init xen_init_apic(void)
-{
-}
 #endif
 
+void __init xen_init_apic(void);
+
 #ifdef CONFIG_XEN_EFI
 extern void xen_efi_init(void);
 #else
index 2a00d349cd6883cba32d9fd477251889a1c58081..d6e5ba3399f0ae151ea040e2ec1fd1df1c3dba6a 100644 (file)
@@ -1831,8 +1831,9 @@ EXPORT_SYMBOL(bio_endio);
  * Allocates and returns a new bio which represents @sectors from the start of
  * @bio, and updates @bio to represent the remaining sectors.
  *
- * The newly allocated bio will point to @bio's bi_io_vec; it is the caller's
- * responsibility to ensure that @bio is not freed before the split.
+ * Unless this is a discard request the newly allocated bio will point
+ * to @bio's bi_io_vec; it is the caller's responsibility to ensure that
+ * @bio is not freed before the split.
  */
 struct bio *bio_split(struct bio *bio, int sectors,
                      gfp_t gfp, struct bio_set *bs)
@@ -1842,7 +1843,15 @@ struct bio *bio_split(struct bio *bio, int sectors,
        BUG_ON(sectors <= 0);
        BUG_ON(sectors >= bio_sectors(bio));
 
-       split = bio_clone_fast(bio, gfp, bs);
+       /*
+        * Discards need a mutable bio_vec to accommodate the payload
+        * required by the DSM TRIM and UNMAP commands.
+        */
+       if (bio->bi_rw & REQ_DISCARD)
+               split = bio_clone_bioset(bio, gfp, bs);
+       else
+               split = bio_clone_fast(bio, gfp, bs);
+
        if (!split)
                return NULL;
 
@@ -2009,6 +2018,7 @@ int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css)
        bio->bi_css = blkcg_css;
        return 0;
 }
+EXPORT_SYMBOL_GPL(bio_associate_blkcg);
 
 /**
  * bio_associate_current - associate a bio with %current
@@ -2039,6 +2049,7 @@ int bio_associate_current(struct bio *bio)
        bio->bi_css = task_get_css(current, blkio_cgrp_id);
        return 0;
 }
+EXPORT_SYMBOL_GPL(bio_associate_current);
 
 /**
  * bio_disassociate_task - undo bio_associate_current()
index 9da02c021ebe2ed296cbdf8560d5bbf2ecd1c48f..d6283b3f5db50674d18ae485970f1e24ed44569d 100644 (file)
@@ -718,8 +718,12 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
                return -EINVAL;
 
        disk = get_gendisk(MKDEV(major, minor), &part);
-       if (!disk || part)
+       if (!disk)
                return -EINVAL;
+       if (part) {
+               put_disk(disk);
+               return -EINVAL;
+       }
 
        rcu_read_lock();
        spin_lock_irq(disk->queue->queue_lock);
index 12600bfffca93f4547e2325eeda9669ff443a7a7..e0057d035200c4dd5e42d191f0395a7769489905 100644 (file)
@@ -241,8 +241,8 @@ EXPORT_SYMBOL(blk_queue_bounce_limit);
  * Description:
  *    Enables a low level driver to set a hard upper limit,
  *    max_hw_sectors, on the size of requests.  max_hw_sectors is set by
- *    the device driver based upon the combined capabilities of I/O
- *    controller and storage device.
+ *    the device driver based upon the capabilities of the I/O
+ *    controller.
  *
  *    max_sectors is a soft limit imposed by the block layer for
  *    filesystem type requests.  This value can be overridden on a
index 717afcdb5f4a9657a9ca6f6af9825e109eba9688..88dbbb115285a3ce54ae5c35260692163bae16ca 100644 (file)
@@ -231,7 +231,7 @@ int acpi_device_set_power(struct acpi_device *device, int state)
                dev_warn(&device->dev, "Failed to change power state to %s\n",
                         acpi_power_state_string(state));
        } else {
-               device->power.state = state;
+               device->power.state = target_state;
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Device [%s] transitioned to %s\n",
                                  device->pnp.bus_id,
index e83fc3d0da9c9c60a99a6dec56cc568a97a0a851..db5d9f79a247c5ceb2cb590f206927c22f6f2b7c 100644 (file)
@@ -2478,6 +2478,10 @@ int ata_dev_configure(struct ata_device *dev)
                dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
                                         dev->max_sectors);
 
+       if (dev->horkage & ATA_HORKAGE_MAX_SEC_1024)
+               dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_1024,
+                                        dev->max_sectors);
+
        if (dev->horkage & ATA_HORKAGE_MAX_SEC_LBA48)
                dev->max_sectors = ATA_MAX_SECTORS_LBA48;
 
@@ -4146,6 +4150,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "Slimtype DVD A  DS8A8SH", NULL,      ATA_HORKAGE_MAX_SEC_LBA48 },
        { "Slimtype DVD A  DS8A9SH", NULL,      ATA_HORKAGE_MAX_SEC_LBA48 },
 
+       /*
+        * Causes silent data corruption with higher max sects.
+        * http://lkml.kernel.org/g/x49wpy40ysk.fsf@segfault.boston.devel.redhat.com
+        */
+       { "ST380013AS",         "3.20",         ATA_HORKAGE_MAX_SEC_1024 },
+
        /* Devices we expect to fail diagnostics */
 
        /* Devices where NCQ should be avoided */
@@ -4174,9 +4184,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "ST3320[68]13AS",     "SD1[5-9]",     ATA_HORKAGE_NONCQ |
                                                ATA_HORKAGE_FIRMWARE_WARN },
 
-       /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */
+       /* drives which fail FPDMA_AA activation (some may freeze afterwards) */
        { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA },
        { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA },
+       { "VB0250EAVER",        "HPG7",         ATA_HORKAGE_BROKEN_FPDMA_AA },
 
        /* Blacklist entries taken from Silicon Image 3124/3132
           Windows driver .inf file - also several Linux problem reports */
@@ -4229,7 +4240,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
                                                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 |
+       { "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, },
@@ -4238,6 +4249,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "Samsung SSD 8*",             NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
 
+       /* devices that don't properly handle TRIM commands */
+       { "SuperSSpeed S238*",          NULL,   ATA_HORKAGE_NOTRIM, },
+
        /*
         * As defined, the DRAT (Deterministic Read After Trim) and RZAT
         * (Return Zero After Trim) flags in the ATA Command Set are
@@ -4501,7 +4515,8 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
        else /* In the ancient relic department - skip all of this */
                return 0;
 
-       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+       /* On some disks, this command causes spin-up, so we need longer timeout */
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 15000);
 
        DPRINTK("EXIT, err_mask=%x\n", err_mask);
        return err_mask;
index 7ccc084bf1dfb8f7b979f5e7ae777e030303d1b8..85aa76116a305eb50d77f2544c87f09914998bed 100644 (file)
@@ -460,6 +460,13 @@ static void sata_pmp_quirks(struct ata_port *ap)
                                       ATA_LFLAG_NO_SRST |
                                       ATA_LFLAG_ASSUME_ATA;
                }
+       } else if (vendor == 0x11ab && devid == 0x4140) {
+               /* Marvell 4140 quirks */
+               ata_for_each_link(link, ap, EDGE) {
+                       /* port 4 is for SEMB device and it doesn't like SRST */
+                       if (link->pmp == 4)
+                               link->flags |= ATA_LFLAG_DISABLED;
+               }
        }
 }
 
index 3131adcc1f87e001f7f8bfe317e92527665e4dd4..641a61a59e89c00036af65d3a31fe2cf67eb22b8 100644 (file)
@@ -2568,7 +2568,8 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
                rbuf[14] = (lowest_aligned >> 8) & 0x3f;
                rbuf[15] = lowest_aligned;
 
-               if (ata_id_has_trim(args->id)) {
+               if (ata_id_has_trim(args->id) &&
+                   !(dev->horkage & ATA_HORKAGE_NOTRIM)) {
                        rbuf[14] |= 0x80; /* LBPME */
 
                        if (ata_id_has_zero_after_trim(args->id) &&
index d6c37bcd416d17145f291136b6e5f2a7192ee404..e2d94972962d69d766e99e8ade594040ae8d9429 100644 (file)
@@ -569,6 +569,8 @@ show_ata_dev_trim(struct device *dev,
 
        if (!ata_id_has_trim(ata_dev->id))
                mode = "unsupported";
+       else if (ata_dev->horkage & ATA_HORKAGE_NOTRIM)
+               mode = "forced_unsupported";
        else if (ata_dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM)
                        mode = "forced_unqueued";
        else if (ata_fpdma_dsm_supported(ata_dev))
index 81751a49d8bf2334612350bba52406b9af352258..56486d92c4e72bd583630baea0fba541f36c926f 100644 (file)
@@ -296,11 +296,20 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
        if (!blk)
                return -ENOMEM;
 
-       present = krealloc(rbnode->cache_present,
-                   BITS_TO_LONGS(blklen) * sizeof(*present), GFP_KERNEL);
-       if (!present) {
-               kfree(blk);
-               return -ENOMEM;
+       if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) {
+               present = krealloc(rbnode->cache_present,
+                                  BITS_TO_LONGS(blklen) * sizeof(*present),
+                                  GFP_KERNEL);
+               if (!present) {
+                       kfree(blk);
+                       return -ENOMEM;
+               }
+
+               memset(present + BITS_TO_LONGS(rbnode->blklen), 0,
+                      (BITS_TO_LONGS(blklen) - BITS_TO_LONGS(rbnode->blklen))
+                      * sizeof(*present));
+       } else {
+               present = rbnode->cache_present;
        }
 
        /* insert the register value in the correct place in the rbnode block */
index 69de41a87b74311b2b7478fb0226b8bc253c6ebc..3177b245d2bdf63e821a12a4c0f18cbab1b16229 100644 (file)
@@ -240,19 +240,19 @@ static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
        while ((entry = llist_del_all(&cq->list)) != NULL) {
                entry = llist_reverse_order(entry);
                do {
+                       struct request_queue *q = NULL;
+
                        cmd = container_of(entry, struct nullb_cmd, ll_list);
                        entry = entry->next;
+                       if (cmd->rq)
+                               q = cmd->rq->q;
                        end_cmd(cmd);
 
-                       if (cmd->rq) {
-                               struct request_queue *q = cmd->rq->q;
-
-                               if (!q->mq_ops && blk_queue_stopped(q)) {
-                                       spin_lock(q->queue_lock);
-                                       if (blk_queue_stopped(q))
-                                               blk_start_queue(q);
-                                       spin_unlock(q->queue_lock);
-                               }
+                       if (q && !q->mq_ops && blk_queue_stopped(q)) {
+                               spin_lock(q->queue_lock);
+                               if (blk_queue_stopped(q))
+                                       blk_start_queue(q);
+                               spin_unlock(q->queue_lock);
                        }
                } while (entry);
        }
index d94529d5c8e951378eaf62d74b708edf271a550f..bc67a93aa4f4749f10d1a219789b21661c01ee21 100644 (file)
@@ -523,6 +523,7 @@ void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...)
 #  define rbd_assert(expr)     ((void) 0)
 #endif /* !RBD_DEBUG */
 
+static void rbd_osd_copyup_callback(struct rbd_obj_request *obj_request);
 static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request);
 static void rbd_img_parent_read(struct rbd_obj_request *obj_request);
 static void rbd_dev_remove_parent(struct rbd_device *rbd_dev);
@@ -1818,6 +1819,16 @@ static void rbd_osd_stat_callback(struct rbd_obj_request *obj_request)
        obj_request_done_set(obj_request);
 }
 
+static void rbd_osd_call_callback(struct rbd_obj_request *obj_request)
+{
+       dout("%s: obj %p\n", __func__, obj_request);
+
+       if (obj_request_img_data_test(obj_request))
+               rbd_osd_copyup_callback(obj_request);
+       else
+               obj_request_done_set(obj_request);
+}
+
 static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
                                struct ceph_msg *msg)
 {
@@ -1866,6 +1877,8 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
                rbd_osd_discard_callback(obj_request);
                break;
        case CEPH_OSD_OP_CALL:
+               rbd_osd_call_callback(obj_request);
+               break;
        case CEPH_OSD_OP_NOTIFY_ACK:
        case CEPH_OSD_OP_WATCH:
                rbd_osd_trivial_callback(obj_request);
@@ -2530,13 +2543,15 @@ out_unwind:
 }
 
 static void
-rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
+rbd_osd_copyup_callback(struct rbd_obj_request *obj_request)
 {
        struct rbd_img_request *img_request;
        struct rbd_device *rbd_dev;
        struct page **pages;
        u32 page_count;
 
+       dout("%s: obj %p\n", __func__, obj_request);
+
        rbd_assert(obj_request->type == OBJ_REQUEST_BIO ||
                obj_request->type == OBJ_REQUEST_NODATA);
        rbd_assert(obj_request_img_data_test(obj_request));
@@ -2563,9 +2578,7 @@ rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
        if (!obj_request->result)
                obj_request->xferred = obj_request->length;
 
-       /* Finish up with the normal image object callback */
-
-       rbd_img_obj_callback(obj_request);
+       obj_request_done_set(obj_request);
 }
 
 static void
@@ -2650,7 +2663,6 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
 
        /* All set, send it off. */
 
-       orig_request->callback = rbd_img_obj_copyup_callback;
        osdc = &rbd_dev->rbd_client->client->osdc;
        img_result = rbd_obj_request_submit(osdc, orig_request);
        if (!img_result)
index ced96777b677b9bcddd65bae004a7a51b5cf0dc3..954c0029fb3babc49d1a1f490f9d420934701e30 100644 (file)
@@ -369,8 +369,8 @@ static void purge_persistent_gnt(struct xen_blkif *blkif)
                return;
        }
 
-       if (work_pending(&blkif->persistent_purge_work)) {
-               pr_alert_ratelimited("Scheduled work from previous purge is still pending, cannot purge list\n");
+       if (work_busy(&blkif->persistent_purge_work)) {
+               pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n");
                return;
        }
 
index 6d89ed35d80c0caaf8bf57ba82c7e9f3a9194bb9..7a8a73f1fc0462feab5bad706573ff6eb4536ef7 100644 (file)
@@ -179,6 +179,7 @@ static DEFINE_SPINLOCK(minor_lock);
        ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
 
 static int blkfront_setup_indirect(struct blkfront_info *info);
+static int blkfront_gather_backend_features(struct blkfront_info *info);
 
 static int get_id_from_freelist(struct blkfront_info *info)
 {
@@ -1128,8 +1129,10 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
                                 * Add the used indirect page back to the list of
                                 * available pages for indirect grefs.
                                 */
-                               indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
-                               list_add(&indirect_page->lru, &info->indirect_pages);
+                               if (!info->feature_persistent) {
+                                       indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
+                                       list_add(&indirect_page->lru, &info->indirect_pages);
+                               }
                                s->indirect_grants[i]->gref = GRANT_INVALID_REF;
                                list_add_tail(&s->indirect_grants[i]->node, &info->grants);
                        }
@@ -1519,7 +1522,7 @@ static int blkif_recover(struct blkfront_info *info)
        info->shadow_free = info->ring.req_prod_pvt;
        info->shadow[BLK_RING_SIZE(info)-1].req.u.rw.id = 0x0fffffff;
 
-       rc = blkfront_setup_indirect(info);
+       rc = blkfront_gather_backend_features(info);
        if (rc) {
                kfree(copy);
                return rc;
@@ -1720,20 +1723,13 @@ static void blkfront_setup_discard(struct blkfront_info *info)
 
 static int blkfront_setup_indirect(struct blkfront_info *info)
 {
-       unsigned int indirect_segments, segs;
+       unsigned int segs;
        int err, i;
 
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-max-indirect-segments", "%u", &indirect_segments,
-                           NULL);
-       if (err) {
-               info->max_indirect_segments = 0;
+       if (info->max_indirect_segments == 0)
                segs = BLKIF_MAX_SEGMENTS_PER_REQUEST;
-       } else {
-               info->max_indirect_segments = min(indirect_segments,
-                                                 xen_blkif_max_segments);
+       else
                segs = info->max_indirect_segments;
-       }
 
        err = fill_grant_buffer(info, (segs + INDIRECT_GREFS(segs)) * BLK_RING_SIZE(info));
        if (err)
@@ -1796,6 +1792,68 @@ out_of_memory:
        return -ENOMEM;
 }
 
+/*
+ * Gather all backend feature-*
+ */
+static int blkfront_gather_backend_features(struct blkfront_info *info)
+{
+       int err;
+       int barrier, flush, discard, persistent;
+       unsigned int indirect_segments;
+
+       info->feature_flush = 0;
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                       "feature-barrier", "%d", &barrier,
+                       NULL);
+
+       /*
+        * If there's no "feature-barrier" defined, then it means
+        * we're dealing with a very old backend which writes
+        * synchronously; nothing to do.
+        *
+        * If there are barriers, then we use flush.
+        */
+       if (!err && barrier)
+               info->feature_flush = REQ_FLUSH | REQ_FUA;
+       /*
+        * And if there is "feature-flush-cache" use that above
+        * barriers.
+        */
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                       "feature-flush-cache", "%d", &flush,
+                       NULL);
+
+       if (!err && flush)
+               info->feature_flush = REQ_FLUSH;
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                       "feature-discard", "%d", &discard,
+                       NULL);
+
+       if (!err && discard)
+               blkfront_setup_discard(info);
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                       "feature-persistent", "%u", &persistent,
+                       NULL);
+       if (err)
+               info->feature_persistent = 0;
+       else
+               info->feature_persistent = persistent;
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                           "feature-max-indirect-segments", "%u", &indirect_segments,
+                           NULL);
+       if (err)
+               info->max_indirect_segments = 0;
+       else
+               info->max_indirect_segments = min(indirect_segments,
+                                                 xen_blkif_max_segments);
+
+       return blkfront_setup_indirect(info);
+}
+
 /*
  * Invoked when the backend is finally 'ready' (and has told produced
  * the details about the physical device - #sectors, size, etc).
@@ -1807,7 +1865,6 @@ static void blkfront_connect(struct blkfront_info *info)
        unsigned int physical_sector_size;
        unsigned int binfo;
        int err;
-       int barrier, flush, discard, persistent;
 
        switch (info->connected) {
        case BLKIF_STATE_CONNECTED:
@@ -1864,48 +1921,7 @@ static void blkfront_connect(struct blkfront_info *info)
        if (err != 1)
                physical_sector_size = sector_size;
 
-       info->feature_flush = 0;
-
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-barrier", "%d", &barrier,
-                           NULL);
-
-       /*
-        * If there's no "feature-barrier" defined, then it means
-        * we're dealing with a very old backend which writes
-        * synchronously; nothing to do.
-        *
-        * If there are barriers, then we use flush.
-        */
-       if (!err && barrier)
-               info->feature_flush = REQ_FLUSH | REQ_FUA;
-       /*
-        * And if there is "feature-flush-cache" use that above
-        * barriers.
-        */
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-flush-cache", "%d", &flush,
-                           NULL);
-
-       if (!err && flush)
-               info->feature_flush = REQ_FLUSH;
-
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-discard", "%d", &discard,
-                           NULL);
-
-       if (!err && discard)
-               blkfront_setup_discard(info);
-
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-persistent", "%u", &persistent,
-                           NULL);
-       if (err)
-               info->feature_persistent = 0;
-       else
-               info->feature_persistent = persistent;
-
-       err = blkfront_setup_indirect(info);
+       err = blkfront_gather_backend_features(info);
        if (err) {
                xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s",
                                 info->xbdev->otherend);
index fb655e8d1e3b17bf4cda9fd09593bc7dc770f78d..763301c7828c72650f2abaa1c723425bdd3c73f4 100644 (file)
@@ -496,10 +496,9 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
        kfree(meta);
 }
 
-static struct zram_meta *zram_meta_alloc(int device_id, u64 disksize)
+static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize)
 {
        size_t num_pages;
-       char pool_name[8];
        struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
 
        if (!meta)
@@ -512,7 +511,6 @@ static struct zram_meta *zram_meta_alloc(int device_id, u64 disksize)
                goto out_error;
        }
 
-       snprintf(pool_name, sizeof(pool_name), "zram%d", device_id);
        meta->mem_pool = zs_create_pool(pool_name, GFP_NOIO | __GFP_HIGHMEM);
        if (!meta->mem_pool) {
                pr_err("Error creating memory pool\n");
@@ -1031,7 +1029,7 @@ static ssize_t disksize_store(struct device *dev,
                return -EINVAL;
 
        disksize = PAGE_ALIGN(disksize);
-       meta = zram_meta_alloc(zram->disk->first_minor, disksize);
+       meta = zram_meta_alloc(zram->disk->disk_name, disksize);
        if (!meta)
                return -ENOMEM;
 
index 1e1a4323a71fd304d410e421b488758d2300b34d..9ceb8ac68fdca2518c953cb6a9a36c6fd5b5f268 100644 (file)
@@ -472,12 +472,11 @@ int btbcm_setup_apple(struct hci_dev *hdev)
 
        /* Read Verbose Config Version Info */
        skb = btbcm_read_verbose_config(hdev);
-       if (IS_ERR(skb))
-               return PTR_ERR(skb);
-
-       BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
-               get_unaligned_le16(skb->data + 5));
-       kfree_skb(skb);
+       if (!IS_ERR(skb)) {
+               BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
+                       get_unaligned_le16(skb->data + 5));
+               kfree_skb(skb);
+       }
 
        set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
 
index da8faf78536a3ae01827a2ee9480c486a04297a5..5643b65cee204d950d842529e0a12123f57e92c0 100644 (file)
@@ -429,7 +429,7 @@ static int hwrng_fillfn(void *unused)
 static void start_khwrngd(void)
 {
        hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
-       if (hwrng_fill == ERR_PTR(-ENOMEM)) {
+       if (IS_ERR(hwrng_fill)) {
                pr_err("hwrng_fill thread creation failed");
                hwrng_fill = NULL;
        }
index 4b93a1efb36d11fa7171735d29bac283e4bb6d97..ac03ba49e9d1952dff14e9383ed86874690a7176 100644 (file)
@@ -126,7 +126,7 @@ PARENTS(pxa3xx_ac97_bus) = { "ring_osc_60mhz", "ac97" };
 PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" };
 PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" };
 
-#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENA : &CKENB)
+#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENB : &CKENA)
 #define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp, \
                    div_hp, bit, is_lp, flags)                          \
        PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp,         \
index b8ff3c64cc452a16fc4108426fb6e5b1c54e91e8..c96de14036a0adebfc7628dc9f9cd5413b5c5495 100644 (file)
@@ -661,6 +661,9 @@ static void sh_cmt_clocksource_suspend(struct clocksource *cs)
 {
        struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
 
+       if (!ch->cs_enabled)
+               return;
+
        sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
        pm_genpd_syscore_poweroff(&ch->cmt->pdev->dev);
 }
@@ -669,6 +672,9 @@ static void sh_cmt_clocksource_resume(struct clocksource *cs)
 {
        struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
 
+       if (!ch->cs_enabled)
+               return;
+
        pm_genpd_syscore_poweron(&ch->cmt->pdev->dev);
        sh_cmt_start(ch, FLAG_CLOCKSOURCE);
 }
index 26063afb3eba41a88f68e753689b05f741f82d36..7a3c30c4336f3cb9b7b67d5965b77175b4cad53f 100644 (file)
@@ -1002,7 +1002,7 @@ static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy)
        int ret = 0;
 
        /* Some related CPUs might not be present (physically hotplugged) */
-       for_each_cpu_and(j, policy->related_cpus, cpu_present_mask) {
+       for_each_cpu(j, policy->real_cpus) {
                if (j == policy->kobj_cpu)
                        continue;
 
@@ -1019,7 +1019,7 @@ static void cpufreq_remove_dev_symlink(struct cpufreq_policy *policy)
        unsigned int j;
 
        /* Some related CPUs might not be present (physically hotplugged) */
-       for_each_cpu_and(j, policy->related_cpus, cpu_present_mask) {
+       for_each_cpu(j, policy->real_cpus) {
                if (j == policy->kobj_cpu)
                        continue;
 
@@ -1163,11 +1163,14 @@ static struct cpufreq_policy *cpufreq_policy_alloc(struct device *dev)
        if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
                goto err_free_cpumask;
 
+       if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
+               goto err_free_rcpumask;
+
        ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &dev->kobj,
                                   "cpufreq");
        if (ret) {
                pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
-               goto err_free_rcpumask;
+               goto err_free_real_cpus;
        }
 
        INIT_LIST_HEAD(&policy->policy_list);
@@ -1184,6 +1187,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(struct device *dev)
 
        return policy;
 
+err_free_real_cpus:
+       free_cpumask_var(policy->real_cpus);
 err_free_rcpumask:
        free_cpumask_var(policy->related_cpus);
 err_free_cpumask:
@@ -1234,6 +1239,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy, bool notify)
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
        cpufreq_policy_put_kobj(policy, notify);
+       free_cpumask_var(policy->real_cpus);
        free_cpumask_var(policy->related_cpus);
        free_cpumask_var(policy->cpus);
        kfree(policy);
@@ -1258,14 +1264,17 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
 
        pr_debug("adding CPU %u\n", cpu);
 
-       /*
-        * Only possible if 'cpu' wasn't physically present earlier and we are
-        * here from subsys_interface add callback. A hotplug notifier will
-        * follow and we will handle it like logical CPU hotplug then. For now,
-        * just create the sysfs link.
-        */
-       if (cpu_is_offline(cpu))
-               return add_cpu_dev_symlink(per_cpu(cpufreq_cpu_data, cpu), cpu);
+       if (cpu_is_offline(cpu)) {
+               /*
+                * Only possible if we are here from the subsys_interface add
+                * callback.  A hotplug notifier will follow and we will handle
+                * it as CPU online then.  For now, just create the sysfs link,
+                * unless there is no policy or the link is already present.
+                */
+               policy = per_cpu(cpufreq_cpu_data, cpu);
+               return policy && !cpumask_test_and_set_cpu(cpu, policy->real_cpus)
+                       ? add_cpu_dev_symlink(policy, cpu) : 0;
+       }
 
        if (!down_read_trylock(&cpufreq_rwsem))
                return 0;
@@ -1307,6 +1316,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
        /* related cpus should atleast have policy->cpus */
        cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
 
+       /* Remember which CPUs have been present at the policy creation time. */
+       if (!recover_policy)
+               cpumask_and(policy->real_cpus, policy->cpus, cpu_present_mask);
+
        /*
         * affected cpus must always be the one, which are online. We aren't
         * managing offline cpus here.
@@ -1420,8 +1433,7 @@ nomem_out:
        return ret;
 }
 
-static int __cpufreq_remove_dev_prepare(struct device *dev,
-                                       struct subsys_interface *sif)
+static int __cpufreq_remove_dev_prepare(struct device *dev)
 {
        unsigned int cpu = dev->id;
        int ret = 0;
@@ -1437,10 +1449,8 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
 
        if (has_target()) {
                ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
-               if (ret) {
+               if (ret)
                        pr_err("%s: Failed to stop governor\n", __func__);
-                       return ret;
-               }
        }
 
        down_write(&policy->rwsem);
@@ -1473,8 +1483,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
        return ret;
 }
 
-static int __cpufreq_remove_dev_finish(struct device *dev,
-                                      struct subsys_interface *sif)
+static int __cpufreq_remove_dev_finish(struct device *dev)
 {
        unsigned int cpu = dev->id;
        int ret;
@@ -1492,10 +1501,8 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
        /* If cpu is last user of policy, free policy */
        if (has_target()) {
                ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
-               if (ret) {
+               if (ret)
                        pr_err("%s: Failed to exit governor\n", __func__);
-                       return ret;
-               }
        }
 
        /*
@@ -1506,10 +1513,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
        if (cpufreq_driver->exit)
                cpufreq_driver->exit(policy);
 
-       /* Free the policy only if the driver is getting removed. */
-       if (sif)
-               cpufreq_policy_free(policy, true);
-
        return 0;
 }
 
@@ -1521,42 +1524,41 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
 static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id;
-       int ret;
-
-       /*
-        * Only possible if 'cpu' is getting physically removed now. A hotplug
-        * notifier should have already been called and we just need to remove
-        * link or free policy here.
-        */
-       if (cpu_is_offline(cpu)) {
-               struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
-               struct cpumask mask;
+       struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
 
-               if (!policy)
-                       return 0;
+       if (!policy)
+               return 0;
 
-               cpumask_copy(&mask, policy->related_cpus);
-               cpumask_clear_cpu(cpu, &mask);
+       if (cpu_online(cpu)) {
+               __cpufreq_remove_dev_prepare(dev);
+               __cpufreq_remove_dev_finish(dev);
+       }
 
-               /*
-                * Free policy only if all policy->related_cpus are removed
-                * physically.
-                */
-               if (cpumask_intersects(&mask, cpu_present_mask)) {
-                       remove_cpu_dev_symlink(policy, cpu);
-                       return 0;
-               }
+       cpumask_clear_cpu(cpu, policy->real_cpus);
 
+       if (cpumask_empty(policy->real_cpus)) {
                cpufreq_policy_free(policy, true);
                return 0;
        }
 
-       ret = __cpufreq_remove_dev_prepare(dev, sif);
+       if (cpu != policy->kobj_cpu) {
+               remove_cpu_dev_symlink(policy, cpu);
+       } else {
+               /*
+                * The CPU owning the policy object is going away.  Move it to
+                * another suitable CPU.
+                */
+               unsigned int new_cpu = cpumask_first(policy->real_cpus);
+               struct device *new_dev = get_cpu_device(new_cpu);
+
+               dev_dbg(dev, "%s: Moving policy object to CPU%u\n", __func__, new_cpu);
 
-       if (!ret)
-               ret = __cpufreq_remove_dev_finish(dev, sif);
+               sysfs_remove_link(&new_dev->kobj, "cpufreq");
+               policy->kobj_cpu = new_cpu;
+               WARN_ON(kobject_move(&policy->kobj, &new_dev->kobj));
+       }
 
-       return ret;
+       return 0;
 }
 
 static void handle_update(struct work_struct *work)
@@ -2395,11 +2397,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
                        break;
 
                case CPU_DOWN_PREPARE:
-                       __cpufreq_remove_dev_prepare(dev, NULL);
+                       __cpufreq_remove_dev_prepare(dev);
                        break;
 
                case CPU_POST_DEAD:
-                       __cpufreq_remove_dev_finish(dev, NULL);
+                       __cpufreq_remove_dev_finish(dev);
                        break;
 
                case CPU_DOWN_FAILED:
index 15ada47bb720b710454795d8d7e83c235c2fccfc..fcb929ec5304a9b233f0d2a55be394e5c1ed25f1 100644 (file)
@@ -681,6 +681,7 @@ static struct cpu_defaults knl_params = {
                .get_max = core_get_max_pstate,
                .get_min = core_get_min_pstate,
                .get_turbo = knl_get_turbo_pstate,
+               .get_scaling = core_get_scaling,
                .set = core_set_pstate,
        },
 };
index e362860c2b50c49ad5289169e68b8baa2a90197c..cd593c1f66dc8af8a6208933003783e0f37b7392 100644 (file)
@@ -20,7 +20,7 @@
 #include <asm/clock.h>
 #include <asm/idle.h>
 
-#include <asm/mach-loongson/loongson.h>
+#include <asm/mach-loongson64/loongson.h>
 
 static uint nowait;
 
index 7ba495f7537042f898ef1cd7cdba7a6263f2059b..402631a19a112770af83f0f4228176703e1c0b44 100644 (file)
@@ -905,7 +905,6 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt)
                crypt->mode |= NPE_OP_NOT_IN_PLACE;
                /* This was never tested by Intel
                 * for more than one dst buffer, I think. */
-               BUG_ON(req->dst->length < nbytes);
                req_ctx->dst = NULL;
                if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook,
                                        flags, DMA_FROM_DEVICE))
index 067402c7c2a93fdc02ca3242f918deba460dae91..df427c0e9e7b2c99c8ee6cbe0c91b98c1ff47c43 100644 (file)
@@ -73,7 +73,8 @@
                                       ICP_QAT_HW_CIPHER_KEY_CONVERT, \
                                       ICP_QAT_HW_CIPHER_DECRYPT)
 
-static atomic_t active_dev;
+static DEFINE_MUTEX(algs_lock);
+static unsigned int active_devs;
 
 struct qat_alg_buf {
        uint32_t len;
@@ -1280,7 +1281,10 @@ static struct crypto_alg qat_algs[] = { {
 
 int qat_algs_register(void)
 {
-       if (atomic_add_return(1, &active_dev) == 1) {
+       int ret = 0;
+
+       mutex_lock(&algs_lock);
+       if (++active_devs == 1) {
                int i;
 
                for (i = 0; i < ARRAY_SIZE(qat_algs); i++)
@@ -1289,21 +1293,25 @@ int qat_algs_register(void)
                                CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC :
                                CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
 
-               return crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs));
+               ret = crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs));
        }
-       return 0;
+       mutex_unlock(&algs_lock);
+       return ret;
 }
 
 int qat_algs_unregister(void)
 {
-       if (atomic_sub_return(1, &active_dev) == 0)
-               return crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs));
-       return 0;
+       int ret = 0;
+
+       mutex_lock(&algs_lock);
+       if (--active_devs == 0)
+               ret = crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs));
+       mutex_unlock(&algs_lock);
+       return ret;
 }
 
 int qat_algs_init(void)
 {
-       atomic_set(&active_dev, 0);
        crypto_get_default_rng();
        return 0;
 }
index 59892126d1758f9d0e0821fa88ff62094a0c6e74..d3629b7482dda55858a942d084916396f6f473c0 100644 (file)
@@ -48,6 +48,8 @@
        BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\
        BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
 
+#define ATC_MAX_DSCR_TRIALS    10
+
 /*
  * Initial number of descriptors to allocate for each channel. This could
  * be increased during dma usage.
@@ -285,28 +287,19 @@ static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
  *
  * @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)
+static inline int atc_calc_bytes_left(int current_len, u32 ctrla)
 {
-       return current_len - ((ctrla & ATC_BTSIZE_MAX) << desc->tx_width);
-}
+       u32 btsize = (ctrla & ATC_BTSIZE_MAX);
+       u32 src_width = ATC_REG_TO_SRC_WIDTH(ctrla);
 
-/**
- * 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);
+       /*
+        * According to the datasheet, when reading the Control A Register
+        * (ctrla), the Buffer Transfer Size (btsize) bitfield refers to the
+        * number of transfers completed on the Source Interface.
+        * So btsize is always a number of source width transfers.
+        */
+       return current_len - (btsize << src_width);
 }
 
 /**
@@ -320,7 +313,7 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
        struct at_desc *desc_first = atc_first_active(atchan);
        struct at_desc *desc;
        int ret;
-       u32 ctrla, dscr;
+       u32 ctrla, dscr, trials;
 
        /*
         * If the cookie doesn't match to the currently running transfer then
@@ -346,15 +339,82 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
                 * the channel's DSCR register and compare it against the value
                 * of the hardware linked list structure of each child
                 * descriptor.
+                *
+                * The CTRLA register provides us with the amount of data
+                * already read from the source for the current child
+                * descriptor. So we can compute a more accurate residue by also
+                * removing the number of bytes corresponding to this amount of
+                * data.
+                *
+                * However, the DSCR and CTRLA registers cannot be read both
+                * atomically. Hence a race condition may occur: the first read
+                * register may refer to one child descriptor whereas the second
+                * read may refer to a later child descriptor in the list
+                * because of the DMA transfer progression inbetween the two
+                * reads.
+                *
+                * One solution could have been to pause the DMA transfer, read
+                * the DSCR and CTRLA then resume the DMA transfer. Nonetheless,
+                * this approach presents some drawbacks:
+                * - If the DMA transfer is paused, RX overruns or TX underruns
+                *   are more likey to occur depending on the system latency.
+                *   Taking the USART driver as an example, it uses a cyclic DMA
+                *   transfer to read data from the Receive Holding Register
+                *   (RHR) to avoid RX overruns since the RHR is not protected
+                *   by any FIFO on most Atmel SoCs. So pausing the DMA transfer
+                *   to compute the residue would break the USART driver design.
+                * - The atc_pause() function masks interrupts but we'd rather
+                *   avoid to do so for system latency purpose.
+                *
+                * Then we'd rather use another solution: the DSCR is read a
+                * first time, the CTRLA is read in turn, next the DSCR is read
+                * a second time. If the two consecutive read values of the DSCR
+                * are the same then we assume both refers to the very same
+                * child descriptor as well as the CTRLA value read inbetween
+                * does. For cyclic tranfers, the assumption is that a full loop
+                * is "not so fast".
+                * If the two DSCR values are different, we read again the CTRLA
+                * then the DSCR till two consecutive read values from DSCR are
+                * equal or till the maxium trials is reach.
+                * This algorithm is very unlikely not to find a stable value for
+                * DSCR.
                 */
 
-               ctrla = channel_readl(atchan, CTRLA);
-               rmb(); /* ensure CTRLA is read before DSCR */
                dscr = channel_readl(atchan, DSCR);
+               rmb(); /* ensure DSCR is read before CTRLA */
+               ctrla = channel_readl(atchan, CTRLA);
+               for (trials = 0; trials < ATC_MAX_DSCR_TRIALS; ++trials) {
+                       u32 new_dscr;
+
+                       rmb(); /* ensure DSCR is read after CTRLA */
+                       new_dscr = channel_readl(atchan, DSCR);
+
+                       /*
+                        * If the DSCR register value has not changed inside the
+                        * DMA controller since the previous read, we assume
+                        * that both the dscr and ctrla values refers to the
+                        * very same descriptor.
+                        */
+                       if (likely(new_dscr == dscr))
+                               break;
+
+                       /*
+                        * DSCR has changed inside the DMA controller, so the
+                        * previouly read value of CTRLA may refer to an already
+                        * processed descriptor hence could be outdated.
+                        * We need to update ctrla to match the current
+                        * descriptor.
+                        */
+                       dscr = new_dscr;
+                       rmb(); /* ensure DSCR is read before CTRLA */
+                       ctrla = channel_readl(atchan, CTRLA);
+               }
+               if (unlikely(trials >= ATC_MAX_DSCR_TRIALS))
+                       return -ETIMEDOUT;
 
                /* for the first descriptor we can be more accurate */
                if (desc_first->lli.dscr == dscr)
-                       return atc_calc_bytes_left(ret, ctrla, desc_first);
+                       return atc_calc_bytes_left(ret, ctrla);
 
                ret -= desc_first->len;
                list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
@@ -365,16 +425,14 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
                }
 
                /*
-                * For the last descriptor in the chain we can calculate
+                * For the current 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.
                 */
-               if (!desc->lli.dscr)
-                       ret = atc_calc_bytes_left_from_reg(ret, atchan, desc);
+               ret = atc_calc_bytes_left(ret, ctrla);
        } else {
                /* single transfer */
-               ret = atc_calc_bytes_left_from_reg(ret, atchan, desc_first);
+               ctrla = channel_readl(atchan, CTRLA);
+               ret = atc_calc_bytes_left(ret, ctrla);
        }
 
        return ret;
@@ -726,7 +784,6 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
 
        desc->txd.cookie = -EBUSY;
        desc->total_len = desc->len = len;
-       desc->tx_width = dwidth;
 
        /* set end-of-link to the last link descriptor of list*/
        set_desc_eol(desc);
@@ -804,10 +861,6 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
        first->txd.cookie = -EBUSY;
        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);
 
@@ -956,10 +1009,6 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        first->txd.cookie = -EBUSY;
        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 */
 
@@ -1077,12 +1126,6 @@ atc_prep_dma_sg(struct dma_chan *chan,
                desc->txd.cookie = 0;
                desc->len = len;
 
-               /*
-                * Although we only need the transfer width for the first and
-                * the last descriptor, its easier to set it to all descriptors.
-                */
-               desc->tx_width = src_width;
-
                atc_desc_chain(&first, &prev, desc);
 
                /* update the lengths and addresses for the next loop cycle */
@@ -1256,7 +1299,6 @@ 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->total_len = buf_len;
-       first->tx_width = reg_width;
 
        return &first->txd;
 
index bc8d5ebedd192f12f9ed32f220c45892c064a8d0..7f5a08230f76de64e044964f8ff49b5051a9bbb2 100644 (file)
 #define                ATC_SRC_WIDTH_BYTE      (0x0 << 24)
 #define                ATC_SRC_WIDTH_HALFWORD  (0x1 << 24)
 #define                ATC_SRC_WIDTH_WORD      (0x2 << 24)
+#define                ATC_REG_TO_SRC_WIDTH(r) (((r) >> 24) & 0x3)
 #define        ATC_DST_WIDTH_MASK      (0x3 << 28)     /* Destination Single Transfer Size */
 #define                ATC_DST_WIDTH(x)        ((x) << 28)
 #define                ATC_DST_WIDTH_BYTE      (0x0 << 28)
@@ -182,7 +183,6 @@ struct at_lli {
  * @txd: support for the async_tx api
  * @desc_node: node on the channed descriptors list
  * @len: descriptor byte count
- * @tx_width: transfer width
  * @total_len: total transaction byte count
  */
 struct at_desc {
@@ -194,7 +194,6 @@ struct at_desc {
        struct dma_async_tx_descriptor  txd;
        struct list_head                desc_node;
        size_t                          len;
-       u32                             tx_width;
        size_t                          total_len;
 
        /* Interleaved data */
index cf1213de7865ecb95e20c9d273a57ec1981203a7..40afa2a16cfc00f17d696833e75d250dabda0e6c 100644 (file)
@@ -359,18 +359,19 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
         * descriptor view 2 since some fields of the configuration register
         * depend on transfer size and src/dest addresses.
         */
-       if (at_xdmac_chan_is_cyclic(atchan)) {
+       if (at_xdmac_chan_is_cyclic(atchan))
                reg = AT_XDMAC_CNDC_NDVIEW_NDV1;
-               at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg);
-       } else if (first->lld.mbr_ubc & AT_XDMAC_MBR_UBC_NDV3) {
+       else if (first->lld.mbr_ubc & AT_XDMAC_MBR_UBC_NDV3)
                reg = AT_XDMAC_CNDC_NDVIEW_NDV3;
-       } else {
-               /*
-                * No need to write AT_XDMAC_CC reg, it will be done when the
-                * descriptor is fecthed.
-                */
+       else
                reg = AT_XDMAC_CNDC_NDVIEW_NDV2;
-       }
+       /*
+        * Even if the register will be updated from the configuration in the
+        * descriptor when using view 2 or higher, the PROT bit won't be set
+        * properly. This bit can be modified only by using the channel
+        * configuration register.
+        */
+       at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg);
 
        reg |= AT_XDMAC_CNDC_NDDUP
               | AT_XDMAC_CNDC_NDSUP
@@ -681,15 +682,16 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        desc->lld.mbr_sa = mem;
                        desc->lld.mbr_da = atchan->sconfig.dst_addr;
                }
-               desc->lld.mbr_cfg = atchan->cfg;
-               dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg);
+               dwidth = at_xdmac_get_dwidth(atchan->cfg);
                fixed_dwidth = IS_ALIGNED(len, 1 << dwidth)
-                              ? at_xdmac_get_dwidth(desc->lld.mbr_cfg)
+                              ? dwidth
                               : AT_XDMAC_CC_DWIDTH_BYTE;
                desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV2                       /* next descriptor view */
                        | AT_XDMAC_MBR_UBC_NDEN                                 /* next descriptor dst parameter update */
                        | AT_XDMAC_MBR_UBC_NSEN                                 /* next descriptor src parameter update */
                        | (len >> fixed_dwidth);                                /* microblock length */
+               desc->lld.mbr_cfg = (atchan->cfg & ~AT_XDMAC_CC_DWIDTH_MASK) |
+                                   AT_XDMAC_CC_DWIDTH(fixed_dwidth);
                dev_dbg(chan2dev(chan),
                         "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
                         __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc);
index fbaf1ead25971542ca81acd9f7ddc14161acf340..f1325f62563e2cdf957f33706d620570202d7faf 100644 (file)
@@ -162,10 +162,11 @@ static void mv_chan_set_mode(struct mv_xor_chan *chan,
        config &= ~0x7;
        config |= op_mode;
 
-       if (IS_ENABLED(__BIG_ENDIAN))
-               config |= XOR_DESCRIPTOR_SWAP;
-       else
-               config &= ~XOR_DESCRIPTOR_SWAP;
+#if defined(__BIG_ENDIAN)
+       config |= XOR_DESCRIPTOR_SWAP;
+#else
+       config &= ~XOR_DESCRIPTOR_SWAP;
+#endif
 
        writel_relaxed(config, XOR_CONFIG(chan));
        chan->current_type = type;
index f513f77b1d85471ff0997f8d9f4755deca293621..ecab4ea059b4d5eec80a3f3354b5c1c2c36343c0 100644 (file)
@@ -2328,7 +2328,7 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
                        desc->txd.callback = last->txd.callback;
                        desc->txd.callback_param = last->txd.callback_param;
                }
-               last->last = false;
+               desc->last = false;
 
                dma_cookie_assign(&desc->txd);
 
@@ -2623,6 +2623,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
                desc->rqcfg.brst_len = 1;
 
        desc->rqcfg.brst_len = get_burst_len(desc, len);
+       desc->bytes_requested = len;
 
        desc->txd.flags = flags;
 
index 7d2c17d8d30fc1a4f1efd9c7471bc1e5cbdc794c..6f80432a3f0a3d74bf9a4612712ad6edf4875edc 100644 (file)
@@ -29,7 +29,7 @@ dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx)
        spin_lock_irqsave(&vc->lock, flags);
        cookie = dma_cookie_assign(tx);
 
-       list_move_tail(&vd->node, &vc->desc_submitted);
+       list_add_tail(&vd->node, &vc->desc_submitted);
        spin_unlock_irqrestore(&vc->lock, flags);
 
        dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: submitted\n",
@@ -83,10 +83,8 @@ static void vchan_complete(unsigned long arg)
                cb_data = vd->tx.callback_param;
 
                list_del(&vd->node);
-               if (async_tx_test_ack(&vd->tx))
-                       list_add(&vd->node, &vc->desc_allocated);
-               else
-                       vc->desc_free(vd);
+
+               vc->desc_free(vd);
 
                if (cb)
                        cb(cb_data);
@@ -98,13 +96,9 @@ void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head)
        while (!list_empty(head)) {
                struct virt_dma_desc *vd = list_first_entry(head,
                        struct virt_dma_desc, node);
-               if (async_tx_test_ack(&vd->tx)) {
-                       list_move_tail(&vd->node, &vc->desc_allocated);
-               } else {
-                       dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd);
-                       list_del(&vd->node);
-                       vc->desc_free(vd);
-               }
+               list_del(&vd->node);
+               dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd);
+               vc->desc_free(vd);
        }
 }
 EXPORT_SYMBOL_GPL(vchan_dma_desc_free_list);
@@ -114,7 +108,6 @@ void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev)
        dma_cookie_init(&vc->chan);
 
        spin_lock_init(&vc->lock);
-       INIT_LIST_HEAD(&vc->desc_allocated);
        INIT_LIST_HEAD(&vc->desc_submitted);
        INIT_LIST_HEAD(&vc->desc_issued);
        INIT_LIST_HEAD(&vc->desc_completed);
index 189e75dbcb15f95876a81848ecde8196a4c82905..181b95267866b605f521860f973aa3860d694fa0 100644 (file)
@@ -29,7 +29,6 @@ struct virt_dma_chan {
        spinlock_t lock;
 
        /* protected by vc.lock */
-       struct list_head desc_allocated;
        struct list_head desc_submitted;
        struct list_head desc_issued;
        struct list_head desc_completed;
@@ -56,16 +55,11 @@ static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan
        struct virt_dma_desc *vd, unsigned long tx_flags)
 {
        extern dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *);
-       unsigned long flags;
 
        dma_async_tx_descriptor_init(&vd->tx, &vc->chan);
        vd->tx.flags = tx_flags;
        vd->tx.tx_submit = vchan_tx_submit;
 
-       spin_lock_irqsave(&vc->lock, flags);
-       list_add_tail(&vd->node, &vc->desc_allocated);
-       spin_unlock_irqrestore(&vc->lock, flags);
-
        return &vd->tx;
 }
 
@@ -128,8 +122,7 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
 }
 
 /**
- * vchan_get_all_descriptors - obtain all allocated, submitted and issued
- *                             descriptors
+ * vchan_get_all_descriptors - obtain all submitted and issued descriptors
  * vc: virtual channel to get descriptors from
  * head: list of descriptors found
  *
@@ -141,7 +134,6 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
 static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
        struct list_head *head)
 {
-       list_splice_tail_init(&vc->desc_allocated, head);
        list_splice_tail_init(&vc->desc_submitted, head);
        list_splice_tail_init(&vc->desc_issued, head);
        list_splice_tail_init(&vc->desc_completed, head);
@@ -149,14 +141,11 @@ static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
 
 static inline void vchan_free_chan_resources(struct virt_dma_chan *vc)
 {
-       struct virt_dma_desc *vd;
        unsigned long flags;
        LIST_HEAD(head);
 
        spin_lock_irqsave(&vc->lock, flags);
        vchan_get_all_descriptors(vc, &head);
-       list_for_each_entry(vd, &head, node)
-               async_tx_clear_ack(&vd->tx);
        spin_unlock_irqrestore(&vc->lock, flags);
 
        vchan_dma_desc_free_list(vc, &head);
index 620fd55ec7660b053a511b8237e54fc46118f407..dff22ab01851aadb37fd434a334cf6cc681cf29c 100644 (file)
 #define XGENE_DMA_MEM_RAM_SHUTDOWN             0xD070
 #define XGENE_DMA_BLK_MEM_RDY                  0xD074
 #define XGENE_DMA_BLK_MEM_RDY_VAL              0xFFFFFFFF
+#define XGENE_DMA_RING_CMD_SM_OFFSET           0x8000
 
 /* X-Gene SoC EFUSE csr register and bit defination */
 #define XGENE_SOC_JTAG1_SHADOW                 0x18
@@ -1887,6 +1888,8 @@ static int xgene_dma_get_resources(struct platform_device *pdev,
                return -ENOMEM;
        }
 
+       pdma->csr_ring_cmd += XGENE_DMA_RING_CMD_SM_OFFSET;
+
        /* Get efuse csr region */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
        if (!res) {
index 3515b381c1312612f56953bc267ee7d5d23b0f84..711d8ad74f116ebdcc7fd3833fbc0672c7a6359b 100644 (file)
@@ -920,7 +920,7 @@ static int ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
         */
 
        for (row = 0; row < mci->nr_csrows; row++) {
-               struct csrow_info *csi = &mci->csrows[row];
+               struct csrow_info *csi = mci->csrows[row];
 
                /*
                 * Get the configuration settings for this
index 080d5cc2705529962d2a62b17fe3f597b5bc41e3..eebdf2a33bfe4b84e1fc1886e7222641f4a56122 100644 (file)
@@ -200,7 +200,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
        status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev);
        if (status) {
                dev_err(&pdev->dev, "failed to register extcon device\n");
-               kfree(palmas_usb->edev->name);
                return status;
        }
 
@@ -214,7 +213,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
                if (status < 0) {
                        dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
                                        palmas_usb->id_irq, status);
-                       kfree(palmas_usb->edev->name);
                        return status;
                }
        }
@@ -229,7 +227,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
                if (status < 0) {
                        dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
                                        palmas_usb->vbus_irq, status);
-                       kfree(palmas_usb->edev->name);
                        return status;
                }
        }
@@ -239,15 +236,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int palmas_usb_remove(struct platform_device *pdev)
-{
-       struct palmas_usb *palmas_usb = platform_get_drvdata(pdev);
-
-       kfree(palmas_usb->edev->name);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int palmas_usb_suspend(struct device *dev)
 {
@@ -288,7 +276,6 @@ static const struct of_device_id of_palmas_match_tbl[] = {
 
 static struct platform_driver palmas_usb_driver = {
        .probe = palmas_usb_probe,
-       .remove = palmas_usb_remove,
        .driver = {
                .name = "palmas-usb",
                .of_match_table = of_palmas_match_tbl,
index 76157ab9faf3ad84a16e738a4e338ad1bded8e3c..43b57b02d050d197fe7994ea744231b7a580eb23 100644 (file)
@@ -124,25 +124,35 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id
        return -EINVAL;
 }
 
-static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
+static int find_cable_id_by_name(struct extcon_dev *edev, const char *name)
 {
-       unsigned int id = EXTCON_NONE;
+       unsigned int id = -EINVAL;
        int i = 0;
 
-       if (edev->max_supported == 0)
-               return -EINVAL;
-
-       /* Find the the number of extcon cable */
+       /* Find the id of extcon cable */
        while (extcon_name[i]) {
                if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) {
                        id = i;
                        break;
                }
+               i++;
        }
 
-       if (id == EXTCON_NONE)
+       return id;
+}
+
+static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
+{
+       unsigned int id;
+
+       if (edev->max_supported == 0)
                return -EINVAL;
 
+       /* Find the the number of extcon cable */
+       id = find_cable_id_by_name(edev, name);
+       if (id < 0)
+               return id;
+
        return find_cable_index_by_id(edev, id);
 }
 
@@ -228,9 +238,11 @@ static ssize_t cable_state_show(struct device *dev,
        struct extcon_cable *cable = container_of(attr, struct extcon_cable,
                                                  attr_state);
 
+       int i = cable->cable_index;
+
        return sprintf(buf, "%d\n",
                       extcon_get_cable_state_(cable->edev,
-                                              cable->cable_index));
+                                              cable->edev->supported_cable[i]));
 }
 
 /**
@@ -263,20 +275,25 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
        spin_lock_irqsave(&edev->lock, flags);
 
        if (edev->state != ((edev->state & ~mask) | (state & mask))) {
+               u32 old_state;
+
                if (check_mutually_exclusive(edev, (edev->state & ~mask) |
                                                   (state & mask))) {
                        spin_unlock_irqrestore(&edev->lock, flags);
                        return -EPERM;
                }
 
-               for (index = 0; index < edev->max_supported; index++) {
-                       if (is_extcon_changed(edev->state, state, index, &attached))
-                               raw_notifier_call_chain(&edev->nh[index], attached, edev);
-               }
-
+               old_state = edev->state;
                edev->state &= ~mask;
                edev->state |= state & mask;
 
+               for (index = 0; index < edev->max_supported; index++) {
+                       if (is_extcon_changed(old_state, edev->state, index,
+                                             &attached))
+                               raw_notifier_call_chain(&edev->nh[index],
+                                                       attached, edev);
+               }
+
                /* This could be in interrupt handler */
                prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
                if (prop_buf) {
@@ -361,8 +378,13 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
  */
 int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
 {
-       return extcon_get_cable_state_(edev, find_cable_index_by_name
-                                               (edev, cable_name));
+       unsigned int id;
+
+       id = find_cable_id_by_name(edev, cable_name);
+       if (id < 0)
+               return id;
+
+       return extcon_get_cable_state_(edev, id);
 }
 EXPORT_SYMBOL_GPL(extcon_get_cable_state);
 
@@ -404,8 +426,13 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
 int extcon_set_cable_state(struct extcon_dev *edev,
                        const char *cable_name, bool cable_state)
 {
-       return extcon_set_cable_state_(edev, find_cable_index_by_name
-                                       (edev, cable_name), cable_state);
+       unsigned int id;
+
+       id = find_cable_id_by_name(edev, cable_name);
+       if (id < 0)
+               return id;
+
+       return extcon_set_cable_state_(edev, id, cable_state);
 }
 EXPORT_SYMBOL_GPL(extcon_set_cable_state);
 
index 4fd9961d552e8a0c12604f1cfef83f2e15bea66d..d4253742543841d6d261dfea22156259b0a13183 100644 (file)
@@ -305,10 +305,17 @@ const char *cper_mem_err_unpack(struct trace_seq *p,
        return ret;
 }
 
-static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem)
+static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
+       int len)
 {
        struct cper_mem_err_compact cmem;
 
+       /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
+       if (len == sizeof(struct cper_sec_mem_err_old) &&
+           (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
+               pr_err(FW_WARN "valid bits set for fields beyond structure\n");
+               return;
+       }
        if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
                printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
        if (mem->validation_bits & CPER_MEM_VALID_PA)
@@ -405,8 +412,10 @@ static void cper_estatus_print_section(
        } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
                struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
                printk("%s""section_type: memory error\n", newpfx);
-               if (gdata->error_data_length >= sizeof(*mem_err))
-                       cper_print_mem(newpfx, mem_err);
+               if (gdata->error_data_length >=
+                   sizeof(struct cper_sec_mem_err_old))
+                       cper_print_mem(newpfx, mem_err,
+                                      gdata->error_data_length);
                else
                        goto err_section_too_small;
        } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
index 9fa8084a7c8d7d9e5aff23bdd372af512e39047a..d6144e3b97c54235ca45a0ad71872957a36ffe48 100644 (file)
@@ -58,6 +58,11 @@ bool efi_runtime_disabled(void)
 
 static int __init parse_efi_cmdline(char *str)
 {
+       if (!str) {
+               pr_warn("need at least one option\n");
+               return -EINVAL;
+       }
+
        if (parse_option_str(str, "noruntime"))
                disable_runtime = true;
 
index c46ca311d8c31d27d2617eb709c1c0776c8568af..86191586340f72f6b466fa6e94a22ffe1558e2e5 100644 (file)
@@ -37,9 +37,29 @@ config DRM_KMS_FB_HELPER
        select FB
        select FRAMEBUFFER_CONSOLE if !EXPERT
        select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE
+       select FB_SYS_FOPS
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        help
          FBDEV helpers for KMS drivers.
 
+config DRM_FBDEV_EMULATION
+       bool "Enable legacy fbdev support for your modesetting driver"
+       depends on DRM
+       select DRM_KMS_HELPER
+       select DRM_KMS_FB_HELPER
+       default y
+       help
+         Choose this option if you have a need for the legacy fbdev
+         support. Note that this support also provides the linux console
+         support on top of your modesetting driver.
+
+         If in doubt, say "Y".
+
 config DRM_LOAD_EDID_FIRMWARE
        bool "Allow to specify an EDID data set instead of probing for it"
        depends on DRM_KMS_HELPER
@@ -79,8 +99,6 @@ config DRM_KMS_CMA_HELPER
 
 source "drivers/gpu/drm/i2c/Kconfig"
 
-source "drivers/gpu/drm/bridge/Kconfig"
-
 config DRM_TDFX
        tristate "3dfx Banshee/Voodoo3+"
        depends on DRM && PCI
@@ -235,6 +253,8 @@ source "drivers/gpu/drm/tegra/Kconfig"
 
 source "drivers/gpu/drm/panel/Kconfig"
 
+source "drivers/gpu/drm/bridge/Kconfig"
+
 source "drivers/gpu/drm/sti/Kconfig"
 
 source "drivers/gpu/drm/amd/amdkfd/Kconfig"
index 5713d0534504c96cc1d218749d385bedcb74d701..8858510437ea089e4fe03e7808811146751e17d8 100644 (file)
@@ -23,7 +23,7 @@ drm-$(CONFIG_OF) += drm_of.o
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
                drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o
 drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
-drm_kms_helper-$(CONFIG_DRM_KMS_FB_HELPER) += drm_fb_helper.o
+drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
 drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
index f3791e0d27d48322ac0c5ba35676a8d07eda0b4d..baefa635169a953f4cb41840b24de11b632e7345 100644 (file)
@@ -1130,6 +1130,9 @@ struct amdgpu_gfx {
        uint32_t                        me_feature_version;
        uint32_t                        ce_feature_version;
        uint32_t                        pfp_feature_version;
+       uint32_t                        rlc_feature_version;
+       uint32_t                        mec_feature_version;
+       uint32_t                        mec2_feature_version;
        struct amdgpu_ring              gfx_ring[AMDGPU_MAX_GFX_RINGS];
        unsigned                        num_gfx_rings;
        struct amdgpu_ring              compute_ring[AMDGPU_MAX_COMPUTE_RINGS];
@@ -1614,6 +1617,9 @@ struct amdgpu_uvd {
 #define AMDGPU_MAX_VCE_HANDLES 16
 #define AMDGPU_VCE_FIRMWARE_OFFSET 256
 
+#define AMDGPU_VCE_HARVEST_VCE0 (1 << 0)
+#define AMDGPU_VCE_HARVEST_VCE1 (1 << 1)
+
 struct amdgpu_vce {
        struct amdgpu_bo        *vcpu_bo;
        uint64_t                gpu_addr;
@@ -1626,6 +1632,7 @@ struct amdgpu_vce {
        const struct firmware   *fw;    /* VCE firmware */
        struct amdgpu_ring      ring[AMDGPU_MAX_VCE_RINGS];
        struct amdgpu_irq_src   irq;
+       unsigned                harvest_config;
 };
 
 /*
@@ -1635,6 +1642,7 @@ struct amdgpu_sdma {
        /* SDMA firmware */
        const struct firmware   *fw;
        uint32_t                fw_version;
+       uint32_t                feature_version;
 
        struct amdgpu_ring      ring;
 };
@@ -1862,6 +1870,12 @@ typedef void (*amdgpu_wreg_t)(struct amdgpu_device*, uint32_t, uint32_t);
 typedef uint32_t (*amdgpu_block_rreg_t)(struct amdgpu_device*, uint32_t, uint32_t);
 typedef void (*amdgpu_block_wreg_t)(struct amdgpu_device*, uint32_t, uint32_t, uint32_t);
 
+struct amdgpu_ip_block_status {
+       bool valid;
+       bool sw;
+       bool hw;
+};
+
 struct amdgpu_device {
        struct device                   *dev;
        struct drm_device               *ddev;
@@ -2004,7 +2018,7 @@ struct amdgpu_device {
 
        const struct amdgpu_ip_block_version *ip_blocks;
        int                             num_ip_blocks;
-       bool                            *ip_block_enabled;
+       struct amdgpu_ip_block_status   *ip_block_status;
        struct mutex    mn_lock;
        DECLARE_HASHTABLE(mn_hash, 7);
 
index 2daad335b8095a1de57f4befb10794db6c0643e4..dd2037bc0b4afa265435cdc3c27b4ddc2af0071b 100644 (file)
@@ -450,7 +450,7 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
 
        while (true) {
                temp = RREG32(mmCP_HQD_ACTIVE);
-               if (temp & CP_HQD_ACTIVE__ACTIVE__SHIFT)
+               if (temp & CP_HQD_ACTIVE__ACTIVE_MASK)
                        break;
                if (timeout == 0) {
                        pr_err("kfd: cp queue preemption time out (%dms)\n",
index d79009b6586713e777d90647aaefec7b9c49b286..99f158e1baffa711073d1251d6d05c72cb68976e 100644 (file)
@@ -1191,8 +1191,9 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
                return -EINVAL;
        }
 
-       adev->ip_block_enabled = kcalloc(adev->num_ip_blocks, sizeof(bool), GFP_KERNEL);
-       if (adev->ip_block_enabled == NULL)
+       adev->ip_block_status = kcalloc(adev->num_ip_blocks,
+                                       sizeof(struct amdgpu_ip_block_status), GFP_KERNEL);
+       if (adev->ip_block_status == NULL)
                return -ENOMEM;
 
        if (adev->ip_blocks == NULL) {
@@ -1203,18 +1204,18 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
        for (i = 0; i < adev->num_ip_blocks; i++) {
                if ((amdgpu_ip_block_mask & (1 << i)) == 0) {
                        DRM_ERROR("disabled ip block: %d\n", i);
-                       adev->ip_block_enabled[i] = false;
+                       adev->ip_block_status[i].valid = false;
                } else {
                        if (adev->ip_blocks[i].funcs->early_init) {
                                r = adev->ip_blocks[i].funcs->early_init((void *)adev);
                                if (r == -ENOENT)
-                                       adev->ip_block_enabled[i] = false;
+                                       adev->ip_block_status[i].valid = false;
                                else if (r)
                                        return r;
                                else
-                                       adev->ip_block_enabled[i] = true;
+                                       adev->ip_block_status[i].valid = true;
                        } else {
-                               adev->ip_block_enabled[i] = true;
+                               adev->ip_block_status[i].valid = true;
                        }
                }
        }
@@ -1227,11 +1228,12 @@ static int amdgpu_init(struct amdgpu_device *adev)
        int i, r;
 
        for (i = 0; i < adev->num_ip_blocks; i++) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].valid)
                        continue;
                r = adev->ip_blocks[i].funcs->sw_init((void *)adev);
                if (r)
                        return r;
+               adev->ip_block_status[i].sw = true;
                /* need to do gmc hw init early so we can allocate gpu mem */
                if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) {
                        r = amdgpu_vram_scratch_init(adev);
@@ -1243,11 +1245,12 @@ static int amdgpu_init(struct amdgpu_device *adev)
                        r = amdgpu_wb_init(adev);
                        if (r)
                                return r;
+                       adev->ip_block_status[i].hw = true;
                }
        }
 
        for (i = 0; i < adev->num_ip_blocks; i++) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].sw)
                        continue;
                /* gmc hw init is done early */
                if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC)
@@ -1255,6 +1258,7 @@ static int amdgpu_init(struct amdgpu_device *adev)
                r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
                if (r)
                        return r;
+               adev->ip_block_status[i].hw = true;
        }
 
        return 0;
@@ -1265,7 +1269,7 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
        int i = 0, r;
 
        for (i = 0; i < adev->num_ip_blocks; i++) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].valid)
                        continue;
                /* enable clockgating to save power */
                r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
@@ -1287,7 +1291,7 @@ static int amdgpu_fini(struct amdgpu_device *adev)
        int i, r;
 
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].hw)
                        continue;
                if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) {
                        amdgpu_wb_fini(adev);
@@ -1300,14 +1304,16 @@ static int amdgpu_fini(struct amdgpu_device *adev)
                        return r;
                r = adev->ip_blocks[i].funcs->hw_fini((void *)adev);
                /* XXX handle errors */
+               adev->ip_block_status[i].hw = false;
        }
 
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].sw)
                        continue;
                r = adev->ip_blocks[i].funcs->sw_fini((void *)adev);
                /* XXX handle errors */
-               adev->ip_block_enabled[i] = false;
+               adev->ip_block_status[i].sw = false;
+               adev->ip_block_status[i].valid = false;
        }
 
        return 0;
@@ -1318,7 +1324,7 @@ static int amdgpu_suspend(struct amdgpu_device *adev)
        int i, r;
 
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].valid)
                        continue;
                /* ungate blocks so that suspend can properly shut them down */
                r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
@@ -1336,7 +1342,7 @@ static int amdgpu_resume(struct amdgpu_device *adev)
        int i, r;
 
        for (i = 0; i < adev->num_ip_blocks; i++) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].valid)
                        continue;
                r = adev->ip_blocks[i].funcs->resume(adev);
                if (r)
@@ -1582,8 +1588,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
        amdgpu_fence_driver_fini(adev);
        amdgpu_fbdev_fini(adev);
        r = amdgpu_fini(adev);
-       kfree(adev->ip_block_enabled);
-       adev->ip_block_enabled = NULL;
+       kfree(adev->ip_block_status);
+       adev->ip_block_status = NULL;
        adev->accel_working = false;
        /* free i2c buses */
        amdgpu_i2c_fini(adev);
index c1645d21f8e244d6d2231073d39f88d0a5a41ca0..81b821247dde5ca4fa3992083813fe848ac97e99 100644 (file)
@@ -53,9 +53,9 @@ static struct fb_ops amdgpufb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = drm_fb_helper_set_par,
-       .fb_fillrect = cfb_fillrect,
-       .fb_copyarea = cfb_copyarea,
-       .fb_imageblit = cfb_imageblit,
+       .fb_fillrect = drm_fb_helper_cfb_fillrect,
+       .fb_copyarea = drm_fb_helper_cfb_copyarea,
+       .fb_imageblit = drm_fb_helper_cfb_imageblit,
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
@@ -179,7 +179,6 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
        struct drm_mode_fb_cmd2 mode_cmd;
        struct drm_gem_object *gobj = NULL;
        struct amdgpu_bo *rbo = NULL;
-       struct device *device = &adev->pdev->dev;
        int ret;
        unsigned long tmp;
 
@@ -201,9 +200,9 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
        rbo = gem_to_amdgpu_bo(gobj);
 
        /* okay we have an object now allocate the framebuffer */
-       info = framebuffer_alloc(0, device);
-       if (info == NULL) {
-               ret = -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info)) {
+               ret = PTR_ERR(info);
                goto out_unref;
        }
 
@@ -212,14 +211,13 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
        ret = amdgpu_framebuffer_init(adev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
        if (ret) {
                DRM_ERROR("failed to initialize framebuffer %d\n", ret);
-               goto out_unref;
+               goto out_destroy_fbi;
        }
 
        fb = &rfbdev->rfb.base;
 
        /* setup helper */
        rfbdev->helper.fb = fb;
-       rfbdev->helper.fbdev = info;
 
        memset_io(rbo->kptr, 0x0, amdgpu_bo_size(rbo));
 
@@ -239,11 +237,6 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
        drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
 
        /* setup aperture base/size for vesafb takeover */
-       info->apertures = alloc_apertures(1);
-       if (!info->apertures) {
-               ret = -ENOMEM;
-               goto out_unref;
-       }
        info->apertures->ranges[0].base = adev->ddev->mode_config.fb_base;
        info->apertures->ranges[0].size = adev->mc.aper_size;
 
@@ -251,13 +244,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
 
        if (info->screen_base == NULL) {
                ret = -ENOSPC;
-               goto out_unref;
-       }
-
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto out_unref;
+               goto out_destroy_fbi;
        }
 
        DRM_INFO("fb mappable at 0x%lX\n",  info->fix.smem_start);
@@ -269,6 +256,8 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
        vga_switcheroo_client_fb_set(adev->ddev->pdev, info);
        return 0;
 
+out_destroy_fbi:
+       drm_fb_helper_release_fbi(helper);
 out_unref:
        if (rbo) {
 
@@ -290,17 +279,10 @@ void amdgpu_fb_output_poll_changed(struct amdgpu_device *adev)
 
 static int amdgpu_fbdev_destroy(struct drm_device *dev, struct amdgpu_fbdev *rfbdev)
 {
-       struct fb_info *info;
        struct amdgpu_framebuffer *rfb = &rfbdev->rfb;
 
-       if (rfbdev->helper.fbdev) {
-               info = rfbdev->helper.fbdev;
-
-               unregister_framebuffer(info);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&rfbdev->helper);
+       drm_fb_helper_release_fbi(&rfbdev->helper);
 
        if (rfb->obj) {
                amdgpufb_destroy_pinned_object(rfb->obj);
@@ -395,7 +377,8 @@ void amdgpu_fbdev_fini(struct amdgpu_device *adev)
 void amdgpu_fbdev_set_suspend(struct amdgpu_device *adev, int state)
 {
        if (adev->mode_info.rfbdev)
-               fb_set_suspend(adev->mode_info.rfbdev->helper.fbdev, state);
+               drm_fb_helper_set_suspend(&adev->mode_info.rfbdev->helper,
+                       state);
 }
 
 int amdgpu_fbdev_total_size(struct amdgpu_device *adev)
index ae43b58c9733a1962cbd6dae4ce42fb8c52fa81a..4afc507820c01db355600631e67f98a3e5d4a644 100644 (file)
@@ -449,7 +449,7 @@ out:
  * vital here, so they are not reported back to userspace.
  */
 static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
-                                   struct amdgpu_bo_va *bo_va)
+                                   struct amdgpu_bo_va *bo_va, uint32_t operation)
 {
        struct ttm_validate_buffer tv, *entry;
        struct amdgpu_bo_list_entry *vm_bos;
@@ -485,7 +485,9 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
        if (r)
                goto error_unlock;
 
-       r = amdgpu_vm_bo_update(adev, bo_va, &bo_va->bo->tbo.mem);
+
+       if (operation == AMDGPU_VA_OP_MAP)
+               r = amdgpu_vm_bo_update(adev, bo_va, &bo_va->bo->tbo.mem);
 
 error_unlock:
        mutex_unlock(&bo_va->vm->mutex);
@@ -580,7 +582,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
        }
 
        if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE))
-               amdgpu_gem_va_update_vm(adev, bo_va);
+               amdgpu_gem_va_update_vm(adev, bo_va, args->operation);
 
        drm_gem_object_unreference_unlocked(gobj);
        return r;
index 52dff75aac6f3e5c3ac04252ec19c122bace0558..bc0fac618a3f01121edb740207b9866b6818f71f 100644 (file)
@@ -180,16 +180,16 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
        if (vm) {
                /* do context switch */
                amdgpu_vm_flush(ring, vm, ib->sync.last_vm_update);
-       }
 
-       if (vm && ring->funcs->emit_gds_switch)
-               amdgpu_ring_emit_gds_switch(ring, ib->vm->ids[ring->idx].id,
-                                           ib->gds_base, ib->gds_size,
-                                           ib->gws_base, ib->gws_size,
-                                           ib->oa_base, ib->oa_size);
+               if (ring->funcs->emit_gds_switch)
+                       amdgpu_ring_emit_gds_switch(ring, ib->vm->ids[ring->idx].id,
+                                                   ib->gds_base, ib->gds_size,
+                                                   ib->gws_base, ib->gws_size,
+                                                   ib->oa_base, ib->oa_size);
 
-       if (ring->funcs->emit_hdp_flush)
-               amdgpu_ring_emit_hdp_flush(ring);
+               if (ring->funcs->emit_hdp_flush)
+                       amdgpu_ring_emit_hdp_flush(ring);
+       }
 
        old_ctx = ring->current_ctx;
        for (i = 0; i < num_ibs; ++i) {
index 8c40a9671b9fb0702765d88d8ee78eddfb040b8c..93000af92283f3619114c4dfd1f0e916f7adeec8 100644 (file)
@@ -242,7 +242,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
 
                for (i = 0; i < adev->num_ip_blocks; i++) {
                        if (adev->ip_blocks[i].type == type &&
-                           adev->ip_block_enabled[i]) {
+                           adev->ip_block_status[i].valid) {
                                ip.hw_ip_version_major = adev->ip_blocks[i].major;
                                ip.hw_ip_version_minor = adev->ip_blocks[i].minor;
                                ip.capabilities_flags = 0;
@@ -281,7 +281,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
 
                for (i = 0; i < adev->num_ip_blocks; i++)
                        if (adev->ip_blocks[i].type == type &&
-                           adev->ip_block_enabled[i] &&
+                           adev->ip_block_status[i].valid &&
                            count < AMDGPU_HW_IP_INSTANCE_MAX_COUNT)
                                count++;
 
@@ -324,16 +324,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                        break;
                case AMDGPU_INFO_FW_GFX_RLC:
                        fw_info.ver = adev->gfx.rlc_fw_version;
-                       fw_info.feature = 0;
+                       fw_info.feature = adev->gfx.rlc_feature_version;
                        break;
                case AMDGPU_INFO_FW_GFX_MEC:
-                       if (info->query_fw.index == 0)
+                       if (info->query_fw.index == 0) {
                                fw_info.ver = adev->gfx.mec_fw_version;
-                       else if (info->query_fw.index == 1)
+                               fw_info.feature = adev->gfx.mec_feature_version;
+                       } else if (info->query_fw.index == 1) {
                                fw_info.ver = adev->gfx.mec2_fw_version;
-                       else
+                               fw_info.feature = adev->gfx.mec2_feature_version;
+                       } else
                                return -EINVAL;
-                       fw_info.feature = 0;
                        break;
                case AMDGPU_INFO_FW_SMC:
                        fw_info.ver = adev->pm.fw_version;
@@ -343,7 +344,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                        if (info->query_fw.index >= 2)
                                return -EINVAL;
                        fw_info.ver = adev->sdma[info->query_fw.index].fw_version;
-                       fw_info.feature = 0;
+                       fw_info.feature = adev->sdma[info->query_fw.index].feature_version;
                        break;
                default:
                        return -EINVAL;
@@ -423,7 +424,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                return n ? -EFAULT : 0;
        }
        case AMDGPU_INFO_DEV_INFO: {
-               struct drm_amdgpu_info_device dev_info;
+               struct drm_amdgpu_info_device dev_info = {};
                struct amdgpu_cu_info cu_info;
 
                dev_info.device_id = dev->pdev->device;
@@ -466,6 +467,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                memcpy(&dev_info.cu_bitmap[0], &cu_info.bitmap[0], sizeof(cu_info.bitmap));
                dev_info.vram_type = adev->mc.vram_type;
                dev_info.vram_bit_width = adev->mc.vram_width;
+               dev_info.vce_harvest_config = adev->vce.harvest_config;
 
                return copy_to_user(out, &dev_info,
                                    min((size_t)size, sizeof(dev_info))) ? -EFAULT : 0;
index 2f7a5efa21c23ab0fda25ee0ebbb360efae966ea..f5c22556ec2c17ff145c48440dfe5e3563e67606 100644 (file)
@@ -374,7 +374,7 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
        unsigned height_in_mb = ALIGN(height / 16, 2);
        unsigned fs_in_mb = width_in_mb * height_in_mb;
 
-       unsigned image_size, tmp, min_dpb_size, num_dpb_buffer;
+       unsigned image_size, tmp, min_dpb_size, num_dpb_buffer, min_ctx_size;
 
        image_size = width * height;
        image_size += image_size / 2;
@@ -466,6 +466,8 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
 
                num_dpb_buffer = (le32_to_cpu(msg[59]) & 0xff) + 2;
                min_dpb_size = image_size * num_dpb_buffer;
+               min_ctx_size = ((width + 255) / 16) * ((height + 255) / 16)
+                                          * 16 * num_dpb_buffer + 52 * 1024;
                break;
 
        default:
@@ -486,6 +488,7 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
 
        buf_sizes[0x1] = dpb_size;
        buf_sizes[0x2] = image_size;
+       buf_sizes[0x4] = min_ctx_size;
        return 0;
 }
 
@@ -628,6 +631,13 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)
                        return -EINVAL;
                }
 
+       } else if (cmd == 0x206) {
+               if ((end - start) < ctx->buf_sizes[4]) {
+                       DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
+                                         (unsigned)(end - start),
+                                         ctx->buf_sizes[4]);
+                       return -EINVAL;
+               }
        } else if ((cmd != 0x100) && (cmd != 0x204)) {
                DRM_ERROR("invalid UVD command %X!\n", cmd);
                return -EINVAL;
@@ -755,9 +765,10 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx)
        struct amdgpu_uvd_cs_ctx ctx = {};
        unsigned buf_sizes[] = {
                [0x00000000]    =       2048,
-               [0x00000001]    =       32 * 1024 * 1024,
-               [0x00000002]    =       2048 * 1152 * 3,
+               [0x00000001]    =       0xFFFFFFFF,
+               [0x00000002]    =       0xFFFFFFFF,
                [0x00000003]    =       2048,
+               [0x00000004]    =       0xFFFFFFFF,
        };
        struct amdgpu_ib *ib = &parser->ibs[ib_idx];
        int r;
index ab83cc1ca4cc04865b0bf918c410a4351496fb22..15df46c93f0a3d9e0810b9018ba761bfaa2cc418 100644 (file)
@@ -500,6 +500,7 @@ static int cik_sdma_load_microcode(struct amdgpu_device *adev)
                amdgpu_ucode_print_sdma_hdr(&hdr->header);
                fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
                adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+               adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
                fw_data = (const __le32 *)
                        (adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
                WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0);
index 1a2d419cbf164e8939cf7e584480dc17c0b93ecb..ace870afc7d45154a6bb6013cb45b773a8e63512 100644 (file)
@@ -494,29 +494,67 @@ static void cz_dpm_fini(struct amdgpu_device *adev)
        amdgpu_free_extended_power_table(adev);
 }
 
+#define ixSMUSVI_NB_CURRENTVID 0xD8230044
+#define CURRENT_NB_VID_MASK 0xff000000
+#define CURRENT_NB_VID__SHIFT 24
+#define ixSMUSVI_GFX_CURRENTVID  0xD8230048
+#define CURRENT_GFX_VID_MASK 0xff000000
+#define CURRENT_GFX_VID__SHIFT 24
+
 static void
 cz_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
                                               struct seq_file *m)
 {
+       struct cz_power_info *pi = cz_get_pi(adev);
        struct amdgpu_clock_voltage_dependency_table *table =
                &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
-       u32 current_index =
-               (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
-               TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX_MASK) >>
-               TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX__SHIFT;
-       u32 sclk, tmp;
-       u16 vddc;
-
-       if (current_index >= NUM_SCLK_LEVELS) {
-               seq_printf(m, "invalid dpm profile %d\n", current_index);
+       struct amdgpu_uvd_clock_voltage_dependency_table *uvd_table =
+               &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+       struct amdgpu_vce_clock_voltage_dependency_table *vce_table =
+               &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+       u32 sclk_index = REG_GET_FIELD(RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX),
+                                      TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
+       u32 uvd_index = REG_GET_FIELD(RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
+                                     TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
+       u32 vce_index = REG_GET_FIELD(RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
+                                     TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
+       u32 sclk, vclk, dclk, ecclk, tmp;
+       u16 vddnb, vddgfx;
+
+       if (sclk_index >= NUM_SCLK_LEVELS) {
+               seq_printf(m, "invalid sclk dpm profile %d\n", sclk_index);
        } else {
-               sclk = table->entries[current_index].clk;
-               tmp = (RREG32_SMC(ixSMU_VOLTAGE_STATUS) &
-                       SMU_VOLTAGE_STATUS__SMU_VOLTAGE_CURRENT_LEVEL_MASK) >>
-                       SMU_VOLTAGE_STATUS__SMU_VOLTAGE_CURRENT_LEVEL__SHIFT;
-               vddc = cz_convert_8bit_index_to_voltage(adev, (u16)tmp);
-               seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
-                          current_index, sclk, vddc);
+               sclk = table->entries[sclk_index].clk;
+               seq_printf(m, "%u sclk: %u\n", sclk_index, sclk);
+       }
+
+       tmp = (RREG32_SMC(ixSMUSVI_NB_CURRENTVID) &
+              CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
+       vddnb = cz_convert_8bit_index_to_voltage(adev, (u16)tmp);
+       tmp = (RREG32_SMC(ixSMUSVI_GFX_CURRENTVID) &
+              CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
+       vddgfx = cz_convert_8bit_index_to_voltage(adev, (u16)tmp);
+       seq_printf(m, "vddnb: %u vddgfx: %u\n", vddnb, vddgfx);
+
+       seq_printf(m, "uvd    %sabled\n", pi->uvd_power_gated ? "dis" : "en");
+       if (!pi->uvd_power_gated) {
+               if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+                       seq_printf(m, "invalid uvd dpm level %d\n", uvd_index);
+               } else {
+                       vclk = uvd_table->entries[uvd_index].vclk;
+                       dclk = uvd_table->entries[uvd_index].dclk;
+                       seq_printf(m, "%u uvd vclk: %u dclk: %u\n", uvd_index, vclk, dclk);
+               }
+       }
+
+       seq_printf(m, "vce    %sabled\n", pi->vce_power_gated ? "dis" : "en");
+       if (!pi->vce_power_gated) {
+               if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+                       seq_printf(m, "invalid vce dpm level %d\n", vce_index);
+               } else {
+                       ecclk = vce_table->entries[vce_index].ecclk;
+                       seq_printf(m, "%u vce ecclk: %u\n", vce_index, ecclk);
+               }
        }
 }
 
index 6e77964f1b640d6841ca216ab2c7f5eed73077f5..e70a26f587a03f7dde6788f88add8f32a25ad764 100644 (file)
@@ -2632,6 +2632,7 @@ static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode)
        struct drm_device *dev = crtc->dev;
        struct amdgpu_device *adev = dev->dev_private;
        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       unsigned type;
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
@@ -2640,6 +2641,9 @@ static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode)
                dce_v10_0_vga_enable(crtc, true);
                amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE);
                dce_v10_0_vga_enable(crtc, false);
+               /* Make sure VBLANK interrupt is still enabled */
+               type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id);
+               amdgpu_irq_update(adev, &adev->crtc_irq, type);
                drm_vblank_post_modeset(dev, amdgpu_crtc->crtc_id);
                dce_v10_0_crtc_load_lut(crtc);
                break;
index 7f7abb0e0be53026d98e074d4c0a756484eb3e1b..dcb402ee048a602ecf03aade115a872212781811 100644 (file)
@@ -2631,6 +2631,7 @@ static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode)
        struct drm_device *dev = crtc->dev;
        struct amdgpu_device *adev = dev->dev_private;
        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       unsigned type;
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
@@ -2639,6 +2640,9 @@ static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode)
                dce_v11_0_vga_enable(crtc, true);
                amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE);
                dce_v11_0_vga_enable(crtc, false);
+               /* Make sure VBLANK interrupt is still enabled */
+               type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id);
+               amdgpu_irq_update(adev, &adev->crtc_irq, type);
                drm_vblank_post_modeset(dev, amdgpu_crtc->crtc_id);
                dce_v11_0_crtc_load_lut(crtc);
                break;
index 2c188fb9fd22ff1a3528673beb8866639d5ef631..0d8bf2cb195603b8be90346a58eabfee62670d23 100644 (file)
@@ -2561,7 +2561,7 @@ static bool gfx_v7_0_ring_emit_semaphore(struct amdgpu_ring *ring,
  * sheduling on the ring.  This function schedules the IB
  * on the gfx ring for execution by the GPU.
  */
-static void gfx_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
+static void gfx_v7_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
                                  struct amdgpu_ib *ib)
 {
        bool need_ctx_switch = ring->current_ctx != ib->ctx;
@@ -2569,15 +2569,10 @@ static void gfx_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
        u32 next_rptr = ring->wptr + 5;
 
        /* drop the CE preamble IB for the same context */
-       if ((ring->type == AMDGPU_RING_TYPE_GFX) &&
-           (ib->flags & AMDGPU_IB_FLAG_PREAMBLE) &&
-           !need_ctx_switch)
+       if ((ib->flags & AMDGPU_IB_FLAG_PREAMBLE) && !need_ctx_switch)
                return;
 
-       if (ring->type == AMDGPU_RING_TYPE_COMPUTE)
-               control |= INDIRECT_BUFFER_VALID;
-
-       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX)
+       if (need_ctx_switch)
                next_rptr += 2;
 
        next_rptr += 4;
@@ -2588,7 +2583,7 @@ static void gfx_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, next_rptr);
 
        /* insert SWITCH_BUFFER packet before first IB in the ring frame */
-       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX) {
+       if (need_ctx_switch) {
                amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
                amdgpu_ring_write(ring, 0);
        }
@@ -2611,6 +2606,35 @@ static void gfx_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, control);
 }
 
+static void gfx_v7_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+                                 struct amdgpu_ib *ib)
+{
+       u32 header, control = 0;
+       u32 next_rptr = ring->wptr + 5;
+
+       control |= INDIRECT_BUFFER_VALID;
+       next_rptr += 4;
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       amdgpu_ring_write(ring, WRITE_DATA_DST_SEL(5) | WR_CONFIRM);
+       amdgpu_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+       amdgpu_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+       amdgpu_ring_write(ring, next_rptr);
+
+       header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
+
+       control |= ib->length_dw |
+                          (ib->vm ? (ib->vm->ids[ring->idx].id << 24) : 0);
+
+       amdgpu_ring_write(ring, header);
+       amdgpu_ring_write(ring,
+#ifdef __BIG_ENDIAN
+                                         (2 << 0) |
+#endif
+                                         (ib->gpu_addr & 0xFFFFFFFC));
+       amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
+       amdgpu_ring_write(ring, control);
+}
+
 /**
  * gfx_v7_0_ring_test_ib - basic ring IB test
  *
@@ -3056,6 +3080,8 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev)
        mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
        amdgpu_ucode_print_gfx_hdr(&mec_hdr->header);
        adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version);
+       adev->gfx.mec_feature_version = le32_to_cpu(
+                                       mec_hdr->ucode_feature_version);
 
        gfx_v7_0_cp_compute_enable(adev, false);
 
@@ -3078,6 +3104,8 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev)
                mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
                amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header);
                adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version);
+               adev->gfx.mec2_feature_version = le32_to_cpu(
+                               mec2_hdr->ucode_feature_version);
 
                /* MEC2 */
                fw_data = (const __le32 *)
@@ -4042,6 +4070,8 @@ static int gfx_v7_0_rlc_resume(struct amdgpu_device *adev)
        hdr = (const struct rlc_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
        amdgpu_ucode_print_rlc_hdr(&hdr->header);
        adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version);
+       adev->gfx.rlc_feature_version = le32_to_cpu(
+                                       hdr->ucode_feature_version);
 
        gfx_v7_0_rlc_stop(adev);
 
@@ -5098,7 +5128,7 @@ static void gfx_v7_0_print_status(void *handle)
                dev_info(adev->dev, "  CP_HPD_EOP_CONTROL=0x%08X\n",
                         RREG32(mmCP_HPD_EOP_CONTROL));
 
-               for (queue = 0; queue < 8; i++) {
+               for (queue = 0; queue < 8; queue++) {
                        cik_srbm_select(adev, me, pipe, queue, 0);
                        dev_info(adev->dev, "  queue: %d\n", queue);
                        dev_info(adev->dev, "  CP_PQ_WPTR_POLL_CNTL=0x%08X\n",
@@ -5555,7 +5585,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = {
        .get_wptr = gfx_v7_0_ring_get_wptr_gfx,
        .set_wptr = gfx_v7_0_ring_set_wptr_gfx,
        .parse_cs = NULL,
-       .emit_ib = gfx_v7_0_ring_emit_ib,
+       .emit_ib = gfx_v7_0_ring_emit_ib_gfx,
        .emit_fence = gfx_v7_0_ring_emit_fence_gfx,
        .emit_semaphore = gfx_v7_0_ring_emit_semaphore,
        .emit_vm_flush = gfx_v7_0_ring_emit_vm_flush,
@@ -5571,7 +5601,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = {
        .get_wptr = gfx_v7_0_ring_get_wptr_compute,
        .set_wptr = gfx_v7_0_ring_set_wptr_compute,
        .parse_cs = NULL,
-       .emit_ib = gfx_v7_0_ring_emit_ib,
+       .emit_ib = gfx_v7_0_ring_emit_ib_compute,
        .emit_fence = gfx_v7_0_ring_emit_fence_compute,
        .emit_semaphore = gfx_v7_0_ring_emit_semaphore,
        .emit_vm_flush = gfx_v7_0_ring_emit_vm_flush,
index 1c7c992dea37a446d66baa91bb25ad60967915e6..20e2cfd521d5352202070f357de89234175cb800 100644 (file)
@@ -587,6 +587,7 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        int err;
        struct amdgpu_firmware_info *info = NULL;
        const struct common_firmware_header *header = NULL;
+       const struct gfx_firmware_header_v1_0 *cp_hdr;
 
        DRM_DEBUG("\n");
 
@@ -611,6 +612,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
+       adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name);
        err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
@@ -619,6 +623,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.me_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
+       adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name);
        err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
@@ -627,12 +634,18 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.ce_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
+       adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
        err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
        if (err)
                goto out;
        err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
+       adev->gfx.rlc_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.rlc_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name);
        err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
@@ -641,6 +654,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.mec_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
+       adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name);
        err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
@@ -648,6 +664,12 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
                err = amdgpu_ucode_validate(adev->gfx.mec2_fw);
                if (err)
                        goto out;
+               cp_hdr = (const struct gfx_firmware_header_v1_0 *)
+                                               adev->gfx.mec2_fw->data;
+               adev->gfx.mec2_fw_version = le32_to_cpu(
+                                               cp_hdr->header.ucode_version);
+               adev->gfx.mec2_feature_version = le32_to_cpu(
+                                               cp_hdr->ucode_feature_version);
        } else {
                err = 0;
                adev->gfx.mec2_fw = NULL;
@@ -1983,6 +2005,7 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                adev->gfx.config.max_shader_engines = 1;
                adev->gfx.config.max_tile_pipes = 2;
                adev->gfx.config.max_sh_per_se = 1;
+               adev->gfx.config.max_backends_per_se = 2;
 
                switch (adev->pdev->revision) {
                case 0xc4:
@@ -1991,7 +2014,6 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                case 0xcc:
                        /* B10 */
                        adev->gfx.config.max_cu_per_sh = 8;
-                       adev->gfx.config.max_backends_per_se = 2;
                        break;
                case 0xc5:
                case 0x81:
@@ -2000,14 +2022,12 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                case 0xcd:
                        /* B8 */
                        adev->gfx.config.max_cu_per_sh = 6;
-                       adev->gfx.config.max_backends_per_se = 2;
                        break;
                case 0xc6:
                case 0xca:
                case 0xce:
                        /* B6 */
                        adev->gfx.config.max_cu_per_sh = 6;
-                       adev->gfx.config.max_backends_per_se = 2;
                        break;
                case 0xc7:
                case 0x87:
@@ -2015,7 +2035,6 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                default:
                        /* B4 */
                        adev->gfx.config.max_cu_per_sh = 4;
-                       adev->gfx.config.max_backends_per_se = 1;
                        break;
                }
 
@@ -2275,7 +2294,6 @@ static int gfx_v8_0_rlc_load_microcode(struct amdgpu_device *adev)
 
        hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data;
        amdgpu_ucode_print_rlc_hdr(&hdr->header);
-       adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version);
 
        fw_data = (const __le32 *)(adev->gfx.rlc_fw->data +
                           le32_to_cpu(hdr->header.ucode_array_offset_bytes));
@@ -2361,12 +2379,6 @@ static int gfx_v8_0_cp_gfx_load_microcode(struct amdgpu_device *adev)
        amdgpu_ucode_print_gfx_hdr(&pfp_hdr->header);
        amdgpu_ucode_print_gfx_hdr(&ce_hdr->header);
        amdgpu_ucode_print_gfx_hdr(&me_hdr->header);
-       adev->gfx.pfp_fw_version = le32_to_cpu(pfp_hdr->header.ucode_version);
-       adev->gfx.ce_fw_version = le32_to_cpu(ce_hdr->header.ucode_version);
-       adev->gfx.me_fw_version = le32_to_cpu(me_hdr->header.ucode_version);
-       adev->gfx.me_feature_version = le32_to_cpu(me_hdr->ucode_feature_version);
-       adev->gfx.ce_feature_version = le32_to_cpu(ce_hdr->ucode_feature_version);
-       adev->gfx.pfp_feature_version = le32_to_cpu(pfp_hdr->ucode_feature_version);
 
        gfx_v8_0_cp_gfx_enable(adev, false);
 
@@ -2622,7 +2634,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev)
 
        mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
        amdgpu_ucode_print_gfx_hdr(&mec_hdr->header);
-       adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version);
 
        fw_data = (const __le32 *)
                (adev->gfx.mec_fw->data +
@@ -2641,7 +2652,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev)
 
                mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
                amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header);
-               adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version);
 
                fw_data = (const __le32 *)
                        (adev->gfx.mec2_fw->data +
@@ -3125,7 +3135,7 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
                                WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER,
                                       AMDGPU_DOORBELL_KIQ << 2);
                                WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER,
-                                               0x7FFFF << 2);
+                                      AMDGPU_DOORBELL_MEC_RING7 << 2);
                        }
                        tmp = RREG32(mmCP_HQD_PQ_DOORBELL_CONTROL);
                        tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
@@ -3753,7 +3763,7 @@ static void gfx_v8_0_ring_emit_hdp_flush(struct amdgpu_ring *ring)
        amdgpu_ring_write(ring, 0x20); /* poll interval */
 }
 
-static void gfx_v8_0_ring_emit_ib(struct amdgpu_ring *ring,
+static void gfx_v8_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
                                  struct amdgpu_ib *ib)
 {
        bool need_ctx_switch = ring->current_ctx != ib->ctx;
@@ -3761,15 +3771,10 @@ static void gfx_v8_0_ring_emit_ib(struct amdgpu_ring *ring,
        u32 next_rptr = ring->wptr + 5;
 
        /* drop the CE preamble IB for the same context */
-       if ((ring->type == AMDGPU_RING_TYPE_GFX) &&
-           (ib->flags & AMDGPU_IB_FLAG_PREAMBLE) &&
-           !need_ctx_switch)
+       if ((ib->flags & AMDGPU_IB_FLAG_PREAMBLE) && !need_ctx_switch)
                return;
 
-       if (ring->type == AMDGPU_RING_TYPE_COMPUTE)
-               control |= INDIRECT_BUFFER_VALID;
-
-       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX)
+       if (need_ctx_switch)
                next_rptr += 2;
 
        next_rptr += 4;
@@ -3780,7 +3785,7 @@ static void gfx_v8_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, next_rptr);
 
        /* insert SWITCH_BUFFER packet before first IB in the ring frame */
-       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX) {
+       if (need_ctx_switch) {
                amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
                amdgpu_ring_write(ring, 0);
        }
@@ -3803,6 +3808,36 @@ static void gfx_v8_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, control);
 }
 
+static void gfx_v8_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+                                 struct amdgpu_ib *ib)
+{
+       u32 header, control = 0;
+       u32 next_rptr = ring->wptr + 5;
+
+       control |= INDIRECT_BUFFER_VALID;
+
+       next_rptr += 4;
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       amdgpu_ring_write(ring, WRITE_DATA_DST_SEL(5) | WR_CONFIRM);
+       amdgpu_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+       amdgpu_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+       amdgpu_ring_write(ring, next_rptr);
+
+       header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
+
+       control |= ib->length_dw |
+                          (ib->vm ? (ib->vm->ids[ring->idx].id << 24) : 0);
+
+       amdgpu_ring_write(ring, header);
+       amdgpu_ring_write(ring,
+#ifdef __BIG_ENDIAN
+                                         (2 << 0) |
+#endif
+                                         (ib->gpu_addr & 0xFFFFFFFC));
+       amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
+       amdgpu_ring_write(ring, control);
+}
+
 static void gfx_v8_0_ring_emit_fence_gfx(struct amdgpu_ring *ring, u64 addr,
                                         u64 seq, unsigned flags)
 {
@@ -4224,7 +4259,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = {
        .get_wptr = gfx_v8_0_ring_get_wptr_gfx,
        .set_wptr = gfx_v8_0_ring_set_wptr_gfx,
        .parse_cs = NULL,
-       .emit_ib = gfx_v8_0_ring_emit_ib,
+       .emit_ib = gfx_v8_0_ring_emit_ib_gfx,
        .emit_fence = gfx_v8_0_ring_emit_fence_gfx,
        .emit_semaphore = gfx_v8_0_ring_emit_semaphore,
        .emit_vm_flush = gfx_v8_0_ring_emit_vm_flush,
@@ -4240,7 +4275,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = {
        .get_wptr = gfx_v8_0_ring_get_wptr_compute,
        .set_wptr = gfx_v8_0_ring_set_wptr_compute,
        .parse_cs = NULL,
-       .emit_ib = gfx_v8_0_ring_emit_ib,
+       .emit_ib = gfx_v8_0_ring_emit_ib_compute,
        .emit_fence = gfx_v8_0_ring_emit_fence_compute,
        .emit_semaphore = gfx_v8_0_ring_emit_semaphore,
        .emit_vm_flush = gfx_v8_0_ring_emit_vm_flush,
index d7895885fe0cf3b3e7cd5d1ae52f291053420b17..a988dfb1d3942e9246361bfd7b97bdabc5e5286c 100644 (file)
@@ -121,6 +121,7 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
        int err, i;
        struct amdgpu_firmware_info *info = NULL;
        const struct common_firmware_header *header = NULL;
+       const struct sdma_firmware_header_v1_0 *hdr;
 
        DRM_DEBUG("\n");
 
@@ -142,6 +143,9 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
                err = amdgpu_ucode_validate(adev->sdma[i].fw);
                if (err)
                        goto out;
+               hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
+               adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+               adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
 
                if (adev->firmware.smu_load) {
                        info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i];
@@ -541,8 +545,6 @@ static int sdma_v2_4_load_microcode(struct amdgpu_device *adev)
                        hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
                        amdgpu_ucode_print_sdma_hdr(&hdr->header);
                        fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
-                       adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
-
                        fw_data = (const __le32 *)
                                (adev->sdma[i].fw->data +
                                 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
index 7bb37b93993fb5312eb2d46189bf09bf789c3989..2b86569b18d3656c87975175a1ff771599c958d6 100644 (file)
@@ -159,6 +159,7 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
        int err, i;
        struct amdgpu_firmware_info *info = NULL;
        const struct common_firmware_header *header = NULL;
+       const struct sdma_firmware_header_v1_0 *hdr;
 
        DRM_DEBUG("\n");
 
@@ -183,6 +184,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
                err = amdgpu_ucode_validate(adev->sdma[i].fw);
                if (err)
                        goto out;
+               hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
+               adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+               adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
 
                if (adev->firmware.smu_load) {
                        info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i];
@@ -630,8 +634,6 @@ static int sdma_v3_0_load_microcode(struct amdgpu_device *adev)
                hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
                amdgpu_ucode_print_sdma_hdr(&hdr->header);
                fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
-               adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
-
                fw_data = (const __le32 *)
                        (adev->sdma[i].fw->data +
                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
index d62c4002e39cc7acc5a3427d0aed92bedf12c984..d1064ca3670ec31376293950c76452414e94ff23 100644 (file)
@@ -35,6 +35,8 @@
 #include "oss/oss_2_0_d.h"
 #include "oss/oss_2_0_sh_mask.h"
 #include "gca/gfx_8_0_d.h"
+#include "smu/smu_7_1_2_d.h"
+#include "smu/smu_7_1_2_sh_mask.h"
 
 #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT    0x04
 #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK      0x10
@@ -112,6 +114,10 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
 
        mutex_lock(&adev->grbm_idx_mutex);
        for (idx = 0; idx < 2; ++idx) {
+
+               if (adev->vce.harvest_config & (1 << idx))
+                       continue;
+
                if(idx == 0)
                        WREG32_P(mmGRBM_GFX_INDEX, 0,
                                ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
@@ -190,10 +196,52 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
        return 0;
 }
 
+#define ixVCE_HARVEST_FUSE_MACRO__ADDRESS     0xC0014074
+#define VCE_HARVEST_FUSE_MACRO__SHIFT       27
+#define VCE_HARVEST_FUSE_MACRO__MASK        0x18000000
+
+static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
+{
+       u32 tmp;
+       unsigned ret;
+
+       if (adev->flags & AMDGPU_IS_APU)
+               tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) &
+                      VCE_HARVEST_FUSE_MACRO__MASK) >>
+                       VCE_HARVEST_FUSE_MACRO__SHIFT;
+       else
+               tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) &
+                      CC_HARVEST_FUSES__VCE_DISABLE_MASK) >>
+                       CC_HARVEST_FUSES__VCE_DISABLE__SHIFT;
+
+       switch (tmp) {
+       case 1:
+               ret = AMDGPU_VCE_HARVEST_VCE0;
+               break;
+       case 2:
+               ret = AMDGPU_VCE_HARVEST_VCE1;
+               break;
+       case 3:
+               ret = AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
+               break;
+       default:
+               ret = 0;
+       }
+
+       return ret;
+}
+
 static int vce_v3_0_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev);
+
+       if ((adev->vce.harvest_config &
+            (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) ==
+           (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
+               return -ENOENT;
+
        vce_v3_0_set_ring_funcs(adev);
        vce_v3_0_set_irq_funcs(adev);
 
index 23ce774ff09d324662c511f14e0188e53f079496..c6f435aa803fd2923e0a5c2b45d1a13f5a069ee5 100644 (file)
@@ -143,7 +143,7 @@ static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q,
                                get_sh_mem_bases_32(qpd_to_pdd(qpd));
        else
                value |= ((get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd))) <<
-                               SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) &&
+                               SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) &
                                SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE_MASK;
 
        q->properties.sdma_vm_addr = value;
index 44c38e8e54d303b0bbb3cbcab51a968882f3589c..7e9cae9d349b5535f973c7825cf356fe48f42d9c 100644 (file)
@@ -155,7 +155,7 @@ static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q,
                                get_sh_mem_bases_32(qpd_to_pdd(qpd));
        else
                value |= ((get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd))) <<
-                               SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) &&
+                               SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) &
                                SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE_MASK;
 
        q->properties.sdma_vm_addr = value;
index 7838e731b0de1be856af431aa3848013a3492e09..7d03c51abcb9d6e3dfc9a277be5ad4141c21606b 100644 (file)
@@ -22,9 +22,9 @@ static /*const*/ struct fb_ops armada_fb_ops = {
        .owner          = THIS_MODULE,
        .fb_check_var   = drm_fb_helper_check_var,
        .fb_set_par     = drm_fb_helper_set_par,
-       .fb_fillrect    = cfb_fillrect,
-       .fb_copyarea    = cfb_copyarea,
-       .fb_imageblit   = cfb_imageblit,
+       .fb_fillrect    = drm_fb_helper_cfb_fillrect,
+       .fb_copyarea    = drm_fb_helper_cfb_copyarea,
+       .fb_imageblit   = drm_fb_helper_cfb_imageblit,
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank       = drm_fb_helper_blank,
        .fb_setcmap     = drm_fb_helper_setcmap,
@@ -80,18 +80,12 @@ static int armada_fb_create(struct drm_fb_helper *fbh,
        if (IS_ERR(dfb))
                return PTR_ERR(dfb);
 
-       info = framebuffer_alloc(0, dev->dev);
-       if (!info) {
-               ret = -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(fbh);
+       if (IS_ERR(info)) {
+               ret = PTR_ERR(info);
                goto err_fballoc;
        }
 
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto err_fbcmap;
-       }
-
        strlcpy(info->fix.id, "armada-drmfb", sizeof(info->fix.id));
        info->par = fbh;
        info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
@@ -101,7 +95,7 @@ static int armada_fb_create(struct drm_fb_helper *fbh,
        info->screen_size = obj->obj.size;
        info->screen_base = ptr;
        fbh->fb = &dfb->fb;
-       fbh->fbdev = info;
+
        drm_fb_helper_fill_fix(info, dfb->fb.pitches[0], dfb->fb.depth);
        drm_fb_helper_fill_var(info, fbh, sizes->fb_width, sizes->fb_height);
 
@@ -111,8 +105,6 @@ static int armada_fb_create(struct drm_fb_helper *fbh,
 
        return 0;
 
- err_fbcmap:
-       framebuffer_release(info);
  err_fballoc:
        dfb->fb.funcs->destroy(&dfb->fb);
        return ret;
@@ -171,6 +163,7 @@ int armada_fbdev_init(struct drm_device *dev)
 
        return 0;
  err_fb_setup:
+       drm_fb_helper_release_fbi(fbh);
        drm_fb_helper_fini(fbh);
  err_fb_helper:
        priv->fbdev = NULL;
@@ -191,14 +184,8 @@ void armada_fbdev_fini(struct drm_device *dev)
        struct drm_fb_helper *fbh = priv->fbdev;
 
        if (fbh) {
-               struct fb_info *info = fbh->fbdev;
-
-               if (info) {
-                       unregister_framebuffer(info);
-                       if (info->cmap.len)
-                               fb_dealloc_cmap(&info->cmap);
-                       framebuffer_release(info);
-               }
+               drm_fb_helper_unregister_fbi(fbh);
+               drm_fb_helper_release_fbi(fbh);
 
                drm_fb_helper_fini(fbh);
 
index ff68eefae27316b87d2cd72020b0639becfc7516..f31db28a684b3e2cbfb042a9aebf11f0bd912105 100644 (file)
@@ -125,7 +125,7 @@ static void ast_fillrect(struct fb_info *info,
                         const struct fb_fillrect *rect)
 {
        struct ast_fbdev *afbdev = info->par;
-       sys_fillrect(info, rect);
+       drm_fb_helper_sys_fillrect(info, rect);
        ast_dirty_update(afbdev, rect->dx, rect->dy, rect->width,
                         rect->height);
 }
@@ -134,7 +134,7 @@ static void ast_copyarea(struct fb_info *info,
                         const struct fb_copyarea *area)
 {
        struct ast_fbdev *afbdev = info->par;
-       sys_copyarea(info, area);
+       drm_fb_helper_sys_copyarea(info, area);
        ast_dirty_update(afbdev, area->dx, area->dy, area->width,
                         area->height);
 }
@@ -143,7 +143,7 @@ static void ast_imageblit(struct fb_info *info,
                          const struct fb_image *image)
 {
        struct ast_fbdev *afbdev = info->par;
-       sys_imageblit(info, image);
+       drm_fb_helper_sys_imageblit(info, image);
        ast_dirty_update(afbdev, image->dx, image->dy, image->width,
                         image->height);
 }
@@ -193,7 +193,6 @@ static int astfb_create(struct drm_fb_helper *helper,
        struct drm_framebuffer *fb;
        struct fb_info *info;
        int size, ret;
-       struct device *device = &dev->pdev->dev;
        void *sysram;
        struct drm_gem_object *gobj = NULL;
        struct ast_bo *bo = NULL;
@@ -217,40 +216,28 @@ static int astfb_create(struct drm_fb_helper *helper,
        if (!sysram)
                return -ENOMEM;
 
-       info = framebuffer_alloc(0, device);
-       if (!info) {
-               ret = -ENOMEM;
-               goto out;
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info)) {
+               ret = PTR_ERR(info);
+               goto err_free_vram;
        }
        info->par = afbdev;
 
        ret = ast_framebuffer_init(dev, &afbdev->afb, &mode_cmd, gobj);
        if (ret)
-               goto out;
+               goto err_release_fbi;
 
        afbdev->sysram = sysram;
        afbdev->size = size;
 
        fb = &afbdev->afb.base;
        afbdev->helper.fb = fb;
-       afbdev->helper.fbdev = info;
 
        strcpy(info->fix.id, "astdrmfb");
 
        info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
        info->fbops = &astfb_ops;
 
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       info->apertures = alloc_apertures(1);
-       if (!info->apertures) {
-               ret = -ENOMEM;
-               goto out;
-       }
        info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0);
        info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
 
@@ -266,7 +253,11 @@ static int astfb_create(struct drm_fb_helper *helper,
                      fb->width, fb->height);
 
        return 0;
-out:
+
+err_release_fbi:
+       drm_fb_helper_release_fbi(helper);
+err_free_vram:
+       vfree(afbdev->sysram);
        return ret;
 }
 
@@ -297,15 +288,10 @@ static const struct drm_fb_helper_funcs ast_fb_helper_funcs = {
 static void ast_fbdev_destroy(struct drm_device *dev,
                              struct ast_fbdev *afbdev)
 {
-       struct fb_info *info;
        struct ast_framebuffer *afb = &afbdev->afb;
-       if (afbdev->helper.fbdev) {
-               info = afbdev->helper.fbdev;
-               unregister_framebuffer(info);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
+
+       drm_fb_helper_unregister_fbi(&afbdev->helper);
+       drm_fb_helper_release_fbi(&afbdev->helper);
 
        if (afb->obj) {
                drm_gem_object_unreference_unlocked(afb->obj);
@@ -377,5 +363,5 @@ void ast_fbdev_set_suspend(struct drm_device *dev, int state)
        if (!ast->fbdev)
                return;
 
-       fb_set_suspend(ast->fbdev->helper.fbdev, state);
+       drm_fb_helper_set_suspend(&ast->fbdev->helper, state);
 }
index 035dacc93382f0923a9d52c645a70cc192a6756e..838217f8ce7dd681de66fa976f8d8bc93b98ece7 100644 (file)
@@ -571,24 +571,18 @@ ast_dumb_mmap_offset(struct drm_file *file,
                     uint64_t *offset)
 {
        struct drm_gem_object *obj;
-       int ret;
        struct ast_bo *bo;
 
-       mutex_lock(&dev->struct_mutex);
        obj = drm_gem_object_lookup(dev, file, handle);
-       if (obj == NULL) {
-               ret = -ENOENT;
-               goto out_unlock;
-       }
+       if (obj == NULL)
+               return -ENOENT;
 
        bo = gem_to_ast_bo(obj);
        *offset = ast_bo_mmap_offset(bo);
 
-       drm_gem_object_unreference(obj);
-       ret = 0;
-out_unlock:
-       mutex_unlock(&dev->struct_mutex);
-       return ret;
+       drm_gem_object_unreference_unlocked(obj);
+
+       return 0;
 
 }
 
index f69b92535505b5ae1c899d6f9b08f76501851fa7..9f6e234e70296a9c35f4877cac98d5ff73b2c73c 100644 (file)
@@ -239,7 +239,8 @@ static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
        return atmel_hlcdc_plane_prepare_disc_area(s);
 }
 
-static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c)
+static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c,
+                                         struct drm_crtc_state *old_s)
 {
        struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
 
@@ -253,7 +254,8 @@ static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c)
        }
 }
 
-static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc)
+static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc,
+                                         struct drm_crtc_state *old_s)
 {
        /* TODO: write common plane control register if available */
 }
@@ -355,6 +357,7 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
                planes->overlays[i]->base.possible_crtcs = 1 << crtc->id;
 
        drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
+       drm_crtc_vblank_reset(&crtc->base);
 
        dc->crtc = &crtc->base;
 
index 60b0c13d7ff5cc6f4c338c9ed3d7f423d684c84e..6fad1f9648f38870b2162cb74a6320f50c34aabc 100644 (file)
@@ -313,20 +313,20 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
 
        pm_runtime_enable(dev->dev);
 
-       ret = atmel_hlcdc_dc_modeset_init(dev);
+       ret = drm_vblank_init(dev, 1);
        if (ret < 0) {
-               dev_err(dev->dev, "failed to initialize mode setting\n");
+               dev_err(dev->dev, "failed to initialize vblank\n");
                goto err_periph_clk_disable;
        }
 
-       drm_mode_config_reset(dev);
-
-       ret = drm_vblank_init(dev, 1);
+       ret = atmel_hlcdc_dc_modeset_init(dev);
        if (ret < 0) {
-               dev_err(dev->dev, "failed to initialize vblank\n");
+               dev_err(dev->dev, "failed to initialize mode setting\n");
                goto err_periph_clk_disable;
        }
 
+       drm_mode_config_reset(dev);
+
        pm_runtime_get_sync(dev->dev);
        ret = drm_irq_install(dev, dc->hlcdc->irq);
        pm_runtime_put_sync(dev->dev);
index 98837bde2d2528356c2764b27fe5ac3721c51817..7f1a3604b19f60295ded6b684159981c651ca322 100644 (file)
@@ -109,7 +109,7 @@ static int bochs_pm_suspend(struct device *dev)
 
        if (bochs->fb.initialized) {
                console_lock();
-               fb_set_suspend(bochs->fb.helper.fbdev, 1);
+               drm_fb_helper_set_suspend(&bochs->fb.helper, 1);
                console_unlock();
        }
 
@@ -126,7 +126,7 @@ static int bochs_pm_resume(struct device *dev)
 
        if (bochs->fb.initialized) {
                console_lock();
-               fb_set_suspend(bochs->fb.helper.fbdev, 0);
+               drm_fb_helper_set_suspend(&bochs->fb.helper, 0);
                console_unlock();
        }
 
index 976d9798dc99d4b1eb498b7d8f2634c35c756a34..09a0637aab3e7e7379efb6ca6aa40329b8f361ad 100644 (file)
@@ -24,9 +24,9 @@ static struct fb_ops bochsfb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = drm_fb_helper_set_par,
-       .fb_fillrect = sys_fillrect,
-       .fb_copyarea = sys_copyarea,
-       .fb_imageblit = sys_imageblit,
+       .fb_fillrect = drm_fb_helper_sys_fillrect,
+       .fb_copyarea = drm_fb_helper_sys_copyarea,
+       .fb_imageblit = drm_fb_helper_sys_imageblit,
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
@@ -56,11 +56,9 @@ static int bochsfb_create(struct drm_fb_helper *helper,
 {
        struct bochs_device *bochs =
                container_of(helper, struct bochs_device, fb.helper);
-       struct drm_device *dev = bochs->dev;
        struct fb_info *info;
        struct drm_framebuffer *fb;
        struct drm_mode_fb_cmd2 mode_cmd;
-       struct device *device = &dev->pdev->dev;
        struct drm_gem_object *gobj = NULL;
        struct bochs_bo *bo = NULL;
        int size, ret;
@@ -106,22 +104,23 @@ static int bochsfb_create(struct drm_fb_helper *helper,
        ttm_bo_unreserve(&bo->bo);
 
        /* init fb device */
-       info = framebuffer_alloc(0, device);
-       if (info == NULL)
-               return -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info))
+               return PTR_ERR(info);
 
        info->par = &bochs->fb.helper;
 
        ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj);
-       if (ret)
+       if (ret) {
+               drm_fb_helper_release_fbi(helper);
                return ret;
+       }
 
        bochs->fb.size = size;
 
        /* setup helper */
        fb = &bochs->fb.gfb.base;
        bochs->fb.helper.fb = fb;
-       bochs->fb.helper.fbdev = info;
 
        strcpy(info->fix.id, "bochsdrmfb");
 
@@ -139,30 +138,17 @@ static int bochsfb_create(struct drm_fb_helper *helper,
        info->fix.smem_start = 0;
        info->fix.smem_len = size;
 
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               DRM_ERROR("%s: can't allocate color map\n", info->fix.id);
-               return -ENOMEM;
-       }
-
        return 0;
 }
 
 static int bochs_fbdev_destroy(struct bochs_device *bochs)
 {
        struct bochs_framebuffer *gfb = &bochs->fb.gfb;
-       struct fb_info *info;
 
        DRM_DEBUG_DRIVER("\n");
 
-       if (bochs->fb.helper.fbdev) {
-               info = bochs->fb.helper.fbdev;
-
-               unregister_framebuffer(info);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&bochs->fb.helper);
+       drm_fb_helper_release_fbi(&bochs->fb.helper);
 
        if (gfb->obj) {
                drm_gem_object_unreference_unlocked(gfb->obj);
index 66286ff518d4be28e8b71b2b8ebf0d0b2ada6496..f69e6bf9bb0e3cd295285f3fbf5ad72c49a3ed93 100644 (file)
@@ -454,25 +454,17 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
                           uint32_t handle, uint64_t *offset)
 {
        struct drm_gem_object *obj;
-       int ret;
        struct bochs_bo *bo;
 
-       mutex_lock(&dev->struct_mutex);
        obj = drm_gem_object_lookup(dev, file, handle);
-       if (obj == NULL) {
-               ret = -ENOENT;
-               goto out_unlock;
-       }
+       if (obj == NULL)
+               return -ENOENT;
 
        bo = gem_to_bochs_bo(obj);
        *offset = bochs_bo_mmap_offset(bo);
 
-       drm_gem_object_unreference(obj);
-       ret = 0;
-out_unlock:
-       mutex_unlock(&dev->struct_mutex);
-       return ret;
-
+       drm_gem_object_unreference_unlocked(obj);
+       return 0;
 }
 
 /* ---------------------------------------------------------------------- */
index acef3223772cb89911c18b2392123fed1bdc28ff..2de52a53a80335a859547956e904851b9249c00c 100644 (file)
@@ -1,24 +1,32 @@
+config DRM_BRIDGE
+       def_bool y
+       depends on DRM
+       help
+         Bridge registration and lookup framework.
+
+menu "Display Interface Bridges"
+       depends on DRM && DRM_BRIDGE
+
 config DRM_DW_HDMI
        tristate
-       depends on DRM
        select DRM_KMS_HELPER
 
-config DRM_PTN3460
-       tristate "PTN3460 DP/LVDS bridge"
-       depends on DRM
+config DRM_NXP_PTN3460
+       tristate "NXP PTN3460 DP/LVDS bridge"
        depends on OF
        select DRM_KMS_HELPER
        select DRM_PANEL
        ---help---
-         ptn3460 eDP-LVDS bridge chip driver.
+         NXP PTN3460 eDP-LVDS bridge chip driver.
 
-config DRM_PS8622
+config DRM_PARADE_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.
+         Parade eDP-LVDS bridge chip driver.
+
+endmenu
index 8dfebd984370e17cac7a76f03e96bac3e7c444a8..e2eef1c2f4c3e0e48f8f28d1834b91dc77d41326 100644 (file)
@@ -1,5 +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
+obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
+obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
index b9140032962d943e658a9bc18af8be8418bc479f..b1619e29a564db97ef626fd2c32bceaa3a18cadc 100644 (file)
@@ -92,7 +92,7 @@ static int cirrus_pm_suspend(struct device *dev)
 
        if (cdev->mode_info.gfbdev) {
                console_lock();
-               fb_set_suspend(cdev->mode_info.gfbdev->helper.fbdev, 1);
+               drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 1);
                console_unlock();
        }
 
@@ -109,7 +109,7 @@ static int cirrus_pm_resume(struct device *dev)
 
        if (cdev->mode_info.gfbdev) {
                console_lock();
-               fb_set_suspend(cdev->mode_info.gfbdev->helper.fbdev, 0);
+               drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 0);
                console_unlock();
        }
 
index 13ddf1c4bb8e45ef5be0ddcdf82d7bad9daf79e9..589103bcc06c05951180711506110ba13b2cd2fc 100644 (file)
@@ -98,7 +98,7 @@ static void cirrus_fillrect(struct fb_info *info,
                         const struct fb_fillrect *rect)
 {
        struct cirrus_fbdev *afbdev = info->par;
-       sys_fillrect(info, rect);
+       drm_fb_helper_sys_fillrect(info, rect);
        cirrus_dirty_update(afbdev, rect->dx, rect->dy, rect->width,
                         rect->height);
 }
@@ -107,7 +107,7 @@ static void cirrus_copyarea(struct fb_info *info,
                         const struct fb_copyarea *area)
 {
        struct cirrus_fbdev *afbdev = info->par;
-       sys_copyarea(info, area);
+       drm_fb_helper_sys_copyarea(info, area);
        cirrus_dirty_update(afbdev, area->dx, area->dy, area->width,
                         area->height);
 }
@@ -116,7 +116,7 @@ static void cirrus_imageblit(struct fb_info *info,
                          const struct fb_image *image)
 {
        struct cirrus_fbdev *afbdev = info->par;
-       sys_imageblit(info, image);
+       drm_fb_helper_sys_imageblit(info, image);
        cirrus_dirty_update(afbdev, image->dx, image->dy, image->width,
                         image->height);
 }
@@ -165,12 +165,10 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
 {
        struct cirrus_fbdev *gfbdev =
                container_of(helper, struct cirrus_fbdev, helper);
-       struct drm_device *dev = gfbdev->helper.dev;
        struct cirrus_device *cdev = gfbdev->helper.dev->dev_private;
        struct fb_info *info;
        struct drm_framebuffer *fb;
        struct drm_mode_fb_cmd2 mode_cmd;
-       struct device *device = &dev->pdev->dev;
        void *sysram;
        struct drm_gem_object *gobj = NULL;
        struct cirrus_bo *bo = NULL;
@@ -195,9 +193,9 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
        if (!sysram)
                return -ENOMEM;
 
-       info = framebuffer_alloc(0, device);
-       if (info == NULL)
-               return -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info))
+               return PTR_ERR(info);
 
        info->par = gfbdev;
 
@@ -216,11 +214,9 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
 
        /* setup helper */
        gfbdev->helper.fb = fb;
-       gfbdev->helper.fbdev = info;
 
        strcpy(info->fix.id, "cirrusdrmfb");
 
-
        info->flags = FBINFO_DEFAULT;
        info->fbops = &cirrusfb_ops;
 
@@ -229,11 +225,6 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
                               sizes->fb_height);
 
        /* setup aperture base/size for vesafb takeover */
-       info->apertures = alloc_apertures(1);
-       if (!info->apertures) {
-               ret = -ENOMEM;
-               goto out_iounmap;
-       }
        info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base;
        info->apertures->ranges[0].size = cdev->mc.vram_size;
 
@@ -246,13 +237,6 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
        info->fix.mmio_start = 0;
        info->fix.mmio_len = 0;
 
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               DRM_ERROR("%s: can't allocate color map\n", info->fix.id);
-               ret = -ENOMEM;
-               goto out_iounmap;
-       }
-
        DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
        DRM_INFO("vram aper at 0x%lX\n", (unsigned long)info->fix.smem_start);
        DRM_INFO("size %lu\n", (unsigned long)info->fix.smem_len);
@@ -260,24 +244,15 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
        DRM_INFO("   pitch is %d\n", fb->pitches[0]);
 
        return 0;
-out_iounmap:
-       return ret;
 }
 
 static int cirrus_fbdev_destroy(struct drm_device *dev,
                                struct cirrus_fbdev *gfbdev)
 {
-       struct fb_info *info;
        struct cirrus_framebuffer *gfb = &gfbdev->gfb;
 
-       if (gfbdev->helper.fbdev) {
-               info = gfbdev->helper.fbdev;
-
-               unregister_framebuffer(info);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&gfbdev->helper);
+       drm_fb_helper_release_fbi(&gfbdev->helper);
 
        if (gfb->obj) {
                drm_gem_object_unreference_unlocked(gfb->obj);
index e4b976658087100304cd76f66330c16b9dcb7271..055fd86ba717d3283c71fbefe398b257ec8e1c20 100644 (file)
@@ -293,25 +293,18 @@ cirrus_dumb_mmap_offset(struct drm_file *file,
                     uint64_t *offset)
 {
        struct drm_gem_object *obj;
-       int ret;
        struct cirrus_bo *bo;
 
-       mutex_lock(&dev->struct_mutex);
        obj = drm_gem_object_lookup(dev, file, handle);
-       if (obj == NULL) {
-               ret = -ENOENT;
-               goto out_unlock;
-       }
+       if (obj == NULL)
+               return -ENOENT;
 
        bo = gem_to_cirrus_bo(obj);
        *offset = cirrus_bo_mmap_offset(bo);
 
-       drm_gem_object_unreference(obj);
-       ret = 0;
-out_unlock:
-       mutex_unlock(&dev->struct_mutex);
-       return ret;
+       drm_gem_object_unreference_unlocked(obj);
 
+       return 0;
 }
 
 bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
index 3efd91c0c6cb07b542fcd82296269b41729cdcad..1066e4b658cf9a341c1955fb34f82040a4be909c 100644 (file)
@@ -153,9 +153,15 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
                if (!connector)
                        continue;
 
-               WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
-
-               connector->funcs->atomic_destroy_state(connector,
+               /*
+                * FIXME: Async commits can race with connector unplugging and
+                * there's currently nothing that prevents cleanup up state for
+                * deleted connectors. As long as the callback doesn't look at
+                * the connector we'll be fine though, so make sure that's the
+                * case by setting all connector pointers to NULL.
+                */
+               state->connector_states[i]->connector = NULL;
+               connector->funcs->atomic_destroy_state(NULL,
                                                       state->connector_states[i]);
                state->connectors[i] = NULL;
                state->connector_states[i] = NULL;
@@ -1224,6 +1230,9 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
                }
        }
 
+       if (ret == 0)
+               ww_acquire_done(&state->acquire_ctx->ww_ctx);
+
        return ret;
 }
 EXPORT_SYMBOL(drm_atomic_check_only);
index 99656815641daaf3159ceae9515abe71f92712d9..d432348837a5131e30e8552b99bd8a70f0a321ba 100644 (file)
@@ -124,7 +124,7 @@ steal_encoder(struct drm_atomic_state *state,
        if (IS_ERR(crtc_state))
                return PTR_ERR(crtc_state);
 
-       crtc_state->mode_changed = true;
+       crtc_state->connectors_changed = true;
 
        list_for_each_entry(connector, &config->connector_list, head) {
                if (connector->state->best_encoder != encoder)
@@ -174,14 +174,14 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
                        idx = drm_crtc_index(connector->state->crtc);
 
                        crtc_state = state->crtc_states[idx];
-                       crtc_state->mode_changed = true;
+                       crtc_state->connectors_changed = true;
                }
 
                if (connector_state->crtc) {
                        idx = drm_crtc_index(connector_state->crtc);
 
                        crtc_state = state->crtc_states[idx];
-                       crtc_state->mode_changed = true;
+                       crtc_state->connectors_changed = true;
                }
        }
 
@@ -196,7 +196,12 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
        }
 
        funcs = connector->helper_private;
-       new_encoder = funcs->best_encoder(connector);
+
+       if (funcs->atomic_best_encoder)
+               new_encoder = funcs->atomic_best_encoder(connector,
+                                                        connector_state);
+       else
+               new_encoder = funcs->best_encoder(connector);
 
        if (!new_encoder) {
                DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
@@ -229,11 +234,14 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
                }
        }
 
+       if (WARN_ON(!connector_state->crtc))
+               return -EINVAL;
+
        connector_state->best_encoder = new_encoder;
        idx = drm_crtc_index(connector_state->crtc);
 
        crtc_state = state->crtc_states[idx];
-       crtc_state->mode_changed = true;
+       crtc_state->connectors_changed = true;
 
        DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n",
                         connector->base.id,
@@ -256,7 +264,8 @@ mode_fixup(struct drm_atomic_state *state)
        bool ret;
 
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               if (!crtc_state->mode_changed)
+               if (!crtc_state->mode_changed &&
+                   !crtc_state->connectors_changed)
                        continue;
 
                drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode);
@@ -298,7 +307,7 @@ mode_fixup(struct drm_atomic_state *state)
                                                 encoder->base.id, encoder->name);
                                return ret;
                        }
-               } else {
+               } else if (funcs->mode_fixup) {
                        ret = funcs->mode_fixup(encoder, &crtc_state->mode,
                                                &crtc_state->adjusted_mode);
                        if (!ret) {
@@ -312,7 +321,8 @@ mode_fixup(struct drm_atomic_state *state)
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
                const struct drm_crtc_helper_funcs *funcs;
 
-               if (!crtc_state->mode_changed)
+               if (!crtc_state->mode_changed &&
+                   !crtc_state->connectors_changed)
                        continue;
 
                funcs = crtc->helper_private;
@@ -338,9 +348,14 @@ mode_fixup(struct drm_atomic_state *state)
  *
  * Check the state object to see if the requested state is physically possible.
  * This does all the crtc and connector related computations for an atomic
- * update. It computes and updates crtc_state->mode_changed, adds any additional
- * connectors needed for full modesets and calls down into ->mode_fixup
- * functions of the driver backend.
+ * update and adds any additional connectors needed for full modesets and calls
+ * down into ->mode_fixup functions of the driver backend.
+ *
+ * crtc_state->mode_changed is set when the input mode is changed.
+ * crtc_state->connectors_changed is set when a connector is added or
+ * removed from the crtc.
+ * crtc_state->active_changed is set when crtc_state->active changes,
+ * which is used for dpms.
  *
  * IMPORTANT:
  *
@@ -373,7 +388,17 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
                if (crtc->state->enable != crtc_state->enable) {
                        DRM_DEBUG_ATOMIC("[CRTC:%d] enable changed\n",
                                         crtc->base.id);
+
+                       /*
+                        * For clarity this assignment is done here, but
+                        * enable == 0 is only true when there are no
+                        * connectors and a NULL mode.
+                        *
+                        * The other way around is true as well. enable != 0
+                        * iff connectors are attached and a mode is set.
+                        */
                        crtc_state->mode_changed = true;
+                       crtc_state->connectors_changed = true;
                }
        }
 
@@ -448,6 +473,9 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
  * This does all the plane update related checks using by calling into the
  * ->atomic_check hooks provided by the driver.
  *
+ * It also sets crtc_state->planes_changed to indicate that a crtc has
+ * updated planes.
+ *
  * RETURNS
  * Zero for success or -errno
  */
@@ -640,15 +668,29 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
        struct drm_crtc_state *old_crtc_state;
        int i;
 
-       /* clear out existing links */
+       /* clear out existing links and update dpms */
        for_each_connector_in_state(old_state, connector, old_conn_state, i) {
-               if (!connector->encoder)
-                       continue;
+               if (connector->encoder) {
+                       WARN_ON(!connector->encoder->crtc);
+
+                       connector->encoder->crtc = NULL;
+                       connector->encoder = NULL;
+               }
 
-               WARN_ON(!connector->encoder->crtc);
+               crtc = connector->state->crtc;
+               if ((!crtc && old_conn_state->crtc) ||
+                   (crtc && drm_atomic_crtc_needs_modeset(crtc->state))) {
+                       struct drm_property *dpms_prop =
+                               dev->mode_config.dpms_property;
+                       int mode = DRM_MODE_DPMS_OFF;
 
-               connector->encoder->crtc = NULL;
-               connector->encoder = NULL;
+                       if (crtc && crtc->state->active)
+                               mode = DRM_MODE_DPMS_ON;
+
+                       connector->dpms = mode;
+                       drm_object_property_set_value(&connector->base,
+                                                     dpms_prop, mode);
+               }
        }
 
        /* set new links */
@@ -924,7 +966,7 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
                        continue;
 
                old_crtc_state->enable = true;
-               old_crtc_state->last_vblank_count = drm_vblank_count(dev, i);
+               old_crtc_state->last_vblank_count = drm_crtc_vblank_count(crtc);
        }
 
        for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
@@ -933,7 +975,7 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
 
                ret = wait_event_timeout(dev->vblank[i].queue,
                                old_crtc_state->last_vblank_count !=
-                                       drm_vblank_count(dev, i),
+                                       drm_crtc_vblank_count(crtc),
                                msecs_to_jiffies(50));
 
                drm_crtc_vblank_put(crtc);
@@ -1144,7 +1186,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
                if (!funcs || !funcs->atomic_begin)
                        continue;
 
-               funcs->atomic_begin(crtc);
+               funcs->atomic_begin(crtc, old_crtc_state);
        }
 
        for_each_plane_in_state(old_state, plane, old_plane_state, i) {
@@ -1174,7 +1216,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
                if (!funcs || !funcs->atomic_flush)
                        continue;
 
-               funcs->atomic_flush(crtc);
+               funcs->atomic_flush(crtc, old_crtc_state);
        }
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
@@ -1210,7 +1252,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state)
 
        crtc_funcs = crtc->helper_private;
        if (crtc_funcs && crtc_funcs->atomic_begin)
-               crtc_funcs->atomic_begin(crtc);
+               crtc_funcs->atomic_begin(crtc, old_crtc_state);
 
        drm_for_each_plane_mask(plane, crtc->dev, plane_mask) {
                struct drm_plane_state *old_plane_state =
@@ -1233,7 +1275,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state)
        }
 
        if (crtc_funcs && crtc_funcs->atomic_flush)
-               crtc_funcs->atomic_flush(crtc);
+               crtc_funcs->atomic_flush(crtc, old_crtc_state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
 
@@ -1954,9 +1996,12 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip);
  * implementing the legacy DPMS connector interface. It computes the new desired
  * ->active state for the corresponding CRTC (if the connector is enabled) and
  *  updates it.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
  */
-void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
-                                     int mode)
+int drm_atomic_helper_connector_dpms(struct drm_connector *connector,
+                                    int mode)
 {
        struct drm_mode_config *config = &connector->dev->mode_config;
        struct drm_atomic_state *state;
@@ -1965,6 +2010,7 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
        struct drm_connector *tmp_connector;
        int ret;
        bool active = false;
+       int old_mode = connector->dpms;
 
        if (mode != DRM_MODE_DPMS_ON)
                mode = DRM_MODE_DPMS_OFF;
@@ -1973,18 +2019,19 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
        crtc = connector->state->crtc;
 
        if (!crtc)
-               return;
+               return 0;
 
-       /* FIXME: ->dpms has no return value so can't forward the -ENOMEM. */
        state = drm_atomic_state_alloc(connector->dev);
        if (!state)
-               return;
+               return -ENOMEM;
 
        state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
 retry:
        crtc_state = drm_atomic_get_crtc_state(state, crtc);
-       if (IS_ERR(crtc_state))
-               return;
+       if (IS_ERR(crtc_state)) {
+               ret = PTR_ERR(crtc_state);
+               goto fail;
+       }
 
        WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
 
@@ -2003,17 +2050,16 @@ retry:
        if (ret != 0)
                goto fail;
 
-       /* Driver takes ownership of state on successful async commit. */
-       return;
+       /* Driver takes ownership of state on successful commit. */
+       return 0;
 fail:
        if (ret == -EDEADLK)
                goto backoff;
 
+       connector->dpms = old_mode;
        drm_atomic_state_free(state);
 
-       WARN(1, "Driver bug: Changing ->active failed with ret=%i\n", ret);
-
-       return;
+       return ret;
 backoff:
        drm_atomic_state_clear(state);
        drm_atomic_legacy_backoff(state);
@@ -2074,6 +2120,7 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
        state->mode_changed = false;
        state->active_changed = false;
        state->planes_changed = false;
+       state->connectors_changed = false;
        state->event = NULL;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
index 1f0da41ae2a150278ab2bc9de7fcf581285e3f08..33d877c65ced6a3c138af9ab47c824038410be0b 100644 (file)
@@ -1151,7 +1151,7 @@ EXPORT_SYMBOL(drm_encoder_cleanup);
 int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
                             unsigned long possible_crtcs,
                             const struct drm_plane_funcs *funcs,
-                            const uint32_t *formats, uint32_t format_count,
+                            const uint32_t *formats, unsigned int format_count,
                             enum drm_plane_type type)
 {
        struct drm_mode_config *config = &dev->mode_config;
@@ -1225,7 +1225,7 @@ EXPORT_SYMBOL(drm_universal_plane_init);
 int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
                   unsigned long possible_crtcs,
                   const struct drm_plane_funcs *funcs,
-                  const uint32_t *formats, uint32_t format_count,
+                  const uint32_t *formats, unsigned int format_count,
                   bool is_primary)
 {
        enum drm_plane_type type;
@@ -4753,9 +4753,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
 
        /* Do DPMS ourselves */
        if (property == connector->dev->mode_config.dpms_property) {
-               if (connector->funcs->dpms)
-                       (*connector->funcs->dpms)(connector, (int)value);
                ret = 0;
+               if (connector->funcs->dpms)
+                       ret = (*connector->funcs->dpms)(connector, (int)value);
        } else if (connector->funcs->set_property)
                ret = connector->funcs->set_property(connector, property, value);
 
@@ -5273,12 +5273,11 @@ void drm_mode_config_reset(struct drm_device *dev)
                if (encoder->funcs->reset)
                        encoder->funcs->reset(encoder);
 
-       drm_for_each_connector(connector, dev) {
-               connector->status = connector_status_unknown;
-
+       mutex_lock(&dev->mode_config.mutex);
+       drm_for_each_connector(connector, dev)
                if (connector->funcs->reset)
                        connector->funcs->reset(connector);
-       }
+       mutex_unlock(&dev->mode_config.mutex);
 }
 EXPORT_SYMBOL(drm_mode_config_reset);
 
index d3d038f05bf7f7ed2bd2d19e3a2db94ff33fe45f..ef534758a02c6f946061107aaa0262527c8a25fb 100644 (file)
@@ -762,15 +762,18 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
  * implementing the DPMS connector attribute. It computes the new desired DPMS
  * state for all encoders and crtcs in the output mesh and calls the ->dpms()
  * callback provided by the driver appropriately.
+ *
+ * Returns:
+ * Always returns 0.
  */
-void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
+int drm_helper_connector_dpms(struct drm_connector *connector, int mode)
 {
        struct drm_encoder *encoder = connector->encoder;
        struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
        int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF;
 
        if (mode == connector->dpms)
-               return;
+               return 0;
 
        old_dpms = connector->dpms;
        connector->dpms = mode;
@@ -802,7 +805,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
                }
        }
 
-       return;
+       return 0;
 }
 EXPORT_SYMBOL(drm_helper_connector_dpms);
 
index 778bbb6425b80c9c8affddad58d993a93755c39e..b0487c9f018cfd09d040ffb08fe4585f68ab6022 100644 (file)
@@ -1294,7 +1294,6 @@ retry:
                                goto retry;
                        }
                        DRM_DEBUG_KMS("failed to dpcd write %d %d\n", tosend, ret);
-                       WARN(1, "fail\n");
 
                        return -EIO;
                }
index e6e05bb75a7715f71d894962ed435e36c9667dc8..05bb7311ac5d151a1893b3802e333f28c8707df4 100644 (file)
@@ -3802,7 +3802,7 @@ int drm_add_modes_noedid(struct drm_connector *connector,
        struct drm_display_mode *mode;
        struct drm_device *dev = connector->dev;
 
-       count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
+       count = ARRAY_SIZE(drm_dmt_modes);
        if (hdisplay < 0)
                hdisplay = 0;
        if (vdisplay < 0)
index f01dc25df2dcb61477f9cb4bbb6537516dda2b58..c19a62561183537046dc896254d09d4ac3a70b1e 100644 (file)
@@ -222,9 +222,9 @@ EXPORT_SYMBOL_GPL(drm_fb_cma_debugfs_show);
 
 static struct fb_ops drm_fbdev_cma_ops = {
        .owner          = THIS_MODULE,
-       .fb_fillrect    = sys_fillrect,
-       .fb_copyarea    = sys_copyarea,
-       .fb_imageblit   = sys_imageblit,
+       .fb_fillrect    = drm_fb_helper_sys_fillrect,
+       .fb_copyarea    = drm_fb_helper_sys_copyarea,
+       .fb_imageblit   = drm_fb_helper_sys_imageblit,
        .fb_check_var   = drm_fb_helper_check_var,
        .fb_set_par     = drm_fb_helper_set_par,
        .fb_blank       = drm_fb_helper_blank,
@@ -263,10 +263,9 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
        if (IS_ERR(obj))
                return -ENOMEM;
 
-       fbi = framebuffer_alloc(0, dev->dev);
-       if (!fbi) {
-               dev_err(dev->dev, "Failed to allocate framebuffer info.\n");
-               ret = -ENOMEM;
+       fbi = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(fbi)) {
+               ret = PTR_ERR(fbi);
                goto err_drm_gem_cma_free_object;
        }
 
@@ -274,23 +273,16 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
        if (IS_ERR(fbdev_cma->fb)) {
                dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
                ret = PTR_ERR(fbdev_cma->fb);
-               goto err_framebuffer_release;
+               goto err_fb_info_destroy;
        }
 
        fb = &fbdev_cma->fb->fb;
        helper->fb = fb;
-       helper->fbdev = fbi;
 
        fbi->par = helper;
        fbi->flags = FBINFO_FLAG_DEFAULT;
        fbi->fbops = &drm_fbdev_cma_ops;
 
-       ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
-       if (ret) {
-               dev_err(dev->dev, "Failed to allocate color map.\n");
-               goto err_drm_fb_cma_destroy;
-       }
-
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
        drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
@@ -305,11 +297,8 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
 
        return 0;
 
-err_drm_fb_cma_destroy:
-       drm_framebuffer_unregister_private(fb);
-       drm_fb_cma_destroy(fb);
-err_framebuffer_release:
-       framebuffer_release(fbi);
+err_fb_info_destroy:
+       drm_fb_helper_release_fbi(helper);
 err_drm_gem_cma_free_object:
        drm_gem_cma_free_object(&obj->base);
        return ret;
@@ -385,20 +374,8 @@ EXPORT_SYMBOL_GPL(drm_fbdev_cma_init);
  */
 void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
 {
-       if (fbdev_cma->fb_helper.fbdev) {
-               struct fb_info *info;
-               int ret;
-
-               info = fbdev_cma->fb_helper.fbdev;
-               ret = unregister_framebuffer(info);
-               if (ret < 0)
-                       DRM_DEBUG_KMS("failed unregister_framebuffer()\n");
-
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper);
+       drm_fb_helper_release_fbi(&fbdev_cma->fb_helper);
 
        if (fbdev_cma->fb) {
                drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
index 73f90f7e2f74407d2b346ce8d37f410624459314..418d299f3b129b307f86a970fdf49d3a826af4c8 100644 (file)
@@ -56,8 +56,8 @@ static LIST_HEAD(kernel_fb_helper_list);
  * Teardown is done with drm_fb_helper_fini().
  *
  * At runtime drivers should restore the fbdev console by calling
- * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They
- * should also notify the fb helper code from updates to the output
+ * drm_fb_helper_restore_fbdev_mode_unlocked() from their ->lastclose callback.
+ * They should also notify the fb helper code from updates to the output
  * configuration by calling drm_fb_helper_hotplug_event(). For easier
  * integration with the output polling code in drm_crtc_helper.c the modeset
  * code provides a ->output_poll_changed callback.
@@ -168,11 +168,14 @@ static void remove_from_modeset(struct drm_mode_set *set,
        }
        set->num_connectors--;
 
-       /* because i915 is pissy about this..
+       /*
         * TODO maybe need to makes sure we set it back to !=NULL somewhere?
         */
-       if (set->num_connectors == 0)
+       if (set->num_connectors == 0) {
                set->fb = NULL;
+               drm_mode_destroy(connector->dev, set->mode);
+               set->mode = NULL;
+       }
 }
 
 int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
@@ -354,21 +357,6 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper)
        }
        return error;
 }
-/**
- * drm_fb_helper_restore_fbdev_mode - restore fbdev configuration
- * @fb_helper: fbcon to restore
- *
- * This should be called from driver's drm ->lastclose callback
- * when implementing an fbcon on top of kms using this helper. This ensures that
- * the user isn't greeted with a black screen when e.g. X dies.
- *
- * Use this variant if you need to bypass locking (panic), or already
- * hold all modeset locks.  Otherwise use drm_fb_helper_restore_fbdev_mode_unlocked()
- */
-static bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
-{
-       return restore_fbdev_mode(fb_helper);
-}
 
 /**
  * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
@@ -398,42 +386,6 @@ bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
 }
 EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
 
-/*
- * restore fbcon display for all kms driver's using this helper, used for sysrq
- * and panic handling.
- */
-static bool drm_fb_helper_force_kernel_mode(void)
-{
-       bool ret, error = false;
-       struct drm_fb_helper *helper;
-
-       if (list_empty(&kernel_fb_helper_list))
-               return false;
-
-       list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
-               struct drm_device *dev = helper->dev;
-
-               if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
-                       continue;
-
-               /*
-                * NOTE: Use trylock mode to avoid deadlocks and sleeping in
-                * panic context.
-                */
-               if (__drm_modeset_lock_all(dev, true) != 0) {
-                       error = true;
-                       continue;
-               }
-
-               ret = drm_fb_helper_restore_fbdev_mode(helper);
-               if (ret)
-                       error = true;
-
-               drm_modeset_unlock_all(dev);
-       }
-       return error;
-}
-
 static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
 {
        struct drm_device *dev = fb_helper->dev;
@@ -459,6 +411,33 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
 }
 
 #ifdef CONFIG_MAGIC_SYSRQ
+/*
+ * restore fbcon display for all kms driver's using this helper, used for sysrq
+ * and panic handling.
+ */
+static bool drm_fb_helper_force_kernel_mode(void)
+{
+       bool ret, error = false;
+       struct drm_fb_helper *helper;
+
+       if (list_empty(&kernel_fb_helper_list))
+               return false;
+
+       list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
+               struct drm_device *dev = helper->dev;
+
+               if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+                       continue;
+
+               drm_modeset_lock_all(dev);
+               ret = restore_fbdev_mode(helper);
+               if (ret)
+                       error = true;
+               drm_modeset_unlock_all(dev);
+       }
+       return error;
+}
+
 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
 {
        bool ret;
@@ -490,14 +469,6 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
        struct drm_connector *connector;
        int i, j;
 
-       /*
-        * fbdev->blank can be called from irq context in case of a panic.
-        * Since we already have our own special panic handler which will
-        * restore the fbdev console mode completely, just bail out early.
-        */
-       if (oops_in_progress)
-               return;
-
        /*
         * For each CRTC in this fb, turn the connectors on/off.
         */
@@ -531,6 +502,9 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
  */
 int drm_fb_helper_blank(int blank, struct fb_info *info)
 {
+       if (oops_in_progress)
+               return -EBUSY;
+
        switch (blank) {
        /* Display: On; HSync: On, VSync: On */
        case FB_BLANK_UNBLANK:
@@ -654,6 +628,86 @@ out_free:
 }
 EXPORT_SYMBOL(drm_fb_helper_init);
 
+/**
+ * drm_fb_helper_alloc_fbi - allocate fb_info and some of its members
+ * @fb_helper: driver-allocated fbdev helper
+ *
+ * A helper to alloc fb_info and the members cmap and apertures. Called
+ * by the driver within the fb_probe fb_helper callback function.
+ *
+ * RETURNS:
+ * fb_info pointer if things went okay, pointer containing error code
+ * otherwise
+ */
+struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
+{
+       struct device *dev = fb_helper->dev->dev;
+       struct fb_info *info;
+       int ret;
+
+       info = framebuffer_alloc(0, dev);
+       if (!info)
+               return ERR_PTR(-ENOMEM);
+
+       ret = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (ret)
+               goto err_release;
+
+       info->apertures = alloc_apertures(1);
+       if (!info->apertures) {
+               ret = -ENOMEM;
+               goto err_free_cmap;
+       }
+
+       fb_helper->fbdev = info;
+
+       return info;
+
+err_free_cmap:
+       fb_dealloc_cmap(&info->cmap);
+err_release:
+       framebuffer_release(info);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(drm_fb_helper_alloc_fbi);
+
+/**
+ * drm_fb_helper_unregister_fbi - unregister fb_info framebuffer device
+ * @fb_helper: driver-allocated fbdev helper
+ *
+ * A wrapper around unregister_framebuffer, to release the fb_info
+ * framebuffer device
+ */
+void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
+{
+       if (fb_helper && fb_helper->fbdev)
+               unregister_framebuffer(fb_helper->fbdev);
+}
+EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
+
+/**
+ * drm_fb_helper_release_fbi - dealloc fb_info and its members
+ * @fb_helper: driver-allocated fbdev helper
+ *
+ * A helper to free memory taken by fb_info and the members cmap and
+ * apertures
+ */
+void drm_fb_helper_release_fbi(struct drm_fb_helper *fb_helper)
+{
+       if (fb_helper) {
+               struct fb_info *info = fb_helper->fbdev;
+
+               if (info) {
+                       if (info->cmap.len)
+                               fb_dealloc_cmap(&info->cmap);
+                       framebuffer_release(info);
+               }
+
+               fb_helper->fbdev = NULL;
+       }
+}
+EXPORT_SYMBOL(drm_fb_helper_release_fbi);
+
 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 {
        if (!list_empty(&fb_helper->kernel_fb_list)) {
@@ -668,6 +722,149 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 }
 EXPORT_SYMBOL(drm_fb_helper_fini);
 
+/**
+ * drm_fb_helper_unlink_fbi - wrapper around unlink_framebuffer
+ * @fb_helper: driver-allocated fbdev helper
+ *
+ * A wrapper around unlink_framebuffer implemented by fbdev core
+ */
+void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
+{
+       if (fb_helper && fb_helper->fbdev)
+               unlink_framebuffer(fb_helper->fbdev);
+}
+EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
+
+/**
+ * drm_fb_helper_sys_read - wrapper around fb_sys_read
+ * @info: fb_info struct pointer
+ * @buf: userspace buffer to read from framebuffer memory
+ * @count: number of bytes to read from framebuffer memory
+ * @ppos: read offset within framebuffer memory
+ *
+ * A wrapper around fb_sys_read implemented by fbdev core
+ */
+ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+       return fb_sys_read(info, buf, count, ppos);
+}
+EXPORT_SYMBOL(drm_fb_helper_sys_read);
+
+/**
+ * drm_fb_helper_sys_write - wrapper around fb_sys_write
+ * @info: fb_info struct pointer
+ * @buf: userspace buffer to write to framebuffer memory
+ * @count: number of bytes to write to framebuffer memory
+ * @ppos: write offset within framebuffer memory
+ *
+ * A wrapper around fb_sys_write implemented by fbdev core
+ */
+ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       return fb_sys_write(info, buf, count, ppos);
+}
+EXPORT_SYMBOL(drm_fb_helper_sys_write);
+
+/**
+ * drm_fb_helper_sys_fillrect - wrapper around sys_fillrect
+ * @info: fbdev registered by the helper
+ * @rect: info about rectangle to fill
+ *
+ * A wrapper around sys_fillrect implemented by fbdev core
+ */
+void drm_fb_helper_sys_fillrect(struct fb_info *info,
+                               const struct fb_fillrect *rect)
+{
+       sys_fillrect(info, rect);
+}
+EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
+
+/**
+ * drm_fb_helper_sys_copyarea - wrapper around sys_copyarea
+ * @info: fbdev registered by the helper
+ * @area: info about area to copy
+ *
+ * A wrapper around sys_copyarea implemented by fbdev core
+ */
+void drm_fb_helper_sys_copyarea(struct fb_info *info,
+                               const struct fb_copyarea *area)
+{
+       sys_copyarea(info, area);
+}
+EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
+
+/**
+ * drm_fb_helper_sys_imageblit - wrapper around sys_imageblit
+ * @info: fbdev registered by the helper
+ * @image: info about image to blit
+ *
+ * A wrapper around sys_imageblit implemented by fbdev core
+ */
+void drm_fb_helper_sys_imageblit(struct fb_info *info,
+                                const struct fb_image *image)
+{
+       sys_imageblit(info, image);
+}
+EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
+
+/**
+ * drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect
+ * @info: fbdev registered by the helper
+ * @rect: info about rectangle to fill
+ *
+ * A wrapper around cfb_imageblit implemented by fbdev core
+ */
+void drm_fb_helper_cfb_fillrect(struct fb_info *info,
+                               const struct fb_fillrect *rect)
+{
+       cfb_fillrect(info, rect);
+}
+EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
+
+/**
+ * drm_fb_helper_cfb_copyarea - wrapper around cfb_copyarea
+ * @info: fbdev registered by the helper
+ * @area: info about area to copy
+ *
+ * A wrapper around cfb_copyarea implemented by fbdev core
+ */
+void drm_fb_helper_cfb_copyarea(struct fb_info *info,
+                               const struct fb_copyarea *area)
+{
+       cfb_copyarea(info, area);
+}
+EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
+
+/**
+ * drm_fb_helper_cfb_imageblit - wrapper around cfb_imageblit
+ * @info: fbdev registered by the helper
+ * @image: info about image to blit
+ *
+ * A wrapper around cfb_imageblit implemented by fbdev core
+ */
+void drm_fb_helper_cfb_imageblit(struct fb_info *info,
+                                const struct fb_image *image)
+{
+       cfb_imageblit(info, image);
+}
+EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
+
+/**
+ * drm_fb_helper_set_suspend - wrapper around fb_set_suspend
+ * @fb_helper: driver-allocated fbdev helper
+ * @state: desired state, zero to resume, non-zero to suspend
+ *
+ * A wrapper around fb_set_suspend implemented by fbdev core
+ */
+void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state)
+{
+       if (fb_helper && fb_helper->fbdev)
+               fb_set_suspend(fb_helper->fbdev, state);
+}
+EXPORT_SYMBOL(drm_fb_helper_set_suspend);
+
 static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
                     u16 blue, u16 regno, struct fb_info *info)
 {
@@ -755,9 +952,10 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
        int i, j, rc = 0;
        int start;
 
-       if (__drm_modeset_lock_all(dev, !!oops_in_progress)) {
+       if (oops_in_progress)
                return -EBUSY;
-       }
+
+       drm_modeset_lock_all(dev);
        if (!drm_fb_helper_is_bound(fb_helper)) {
                drm_modeset_unlock_all(dev);
                return -EBUSY;
@@ -906,6 +1104,9 @@ int drm_fb_helper_set_par(struct fb_info *info)
        struct drm_fb_helper *fb_helper = info->par;
        struct fb_var_screeninfo *var = &info->var;
 
+       if (oops_in_progress)
+               return -EBUSY;
+
        if (var->pixclock != 0) {
                DRM_ERROR("PIXEL CLOCK SET\n");
                return -EINVAL;
@@ -931,9 +1132,10 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
        int ret = 0;
        int i;
 
-       if (__drm_modeset_lock_all(dev, !!oops_in_progress)) {
+       if (oops_in_progress)
                return -EBUSY;
-       }
+
+       drm_modeset_lock_all(dev);
        if (!drm_fb_helper_is_bound(fb_helper)) {
                drm_modeset_unlock_all(dev);
                return -EBUSY;
index 27a4228b43431b05da2fcd3138a9c33ab861d73a..3c2d4abd71c5eb3a82b204f28d8455ddb94a6add 100644 (file)
@@ -766,7 +766,7 @@ drm_gem_object_free(struct kref *kref)
        struct drm_gem_object *obj = (struct drm_gem_object *) kref;
        struct drm_device *dev = obj->dev;
 
-       BUG_ON(!mutex_is_locked(&dev->struct_mutex));
+       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
        if (dev->driver->gem_free_object != NULL)
                dev->driver->gem_free_object(obj);
index 9edad11dca9852f551138b180b4eddbdc32038f2..86cc793cdf79d154b2caad7eb42a99e595812954 100644 (file)
@@ -289,20 +289,15 @@ int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv,
 {
        struct drm_gem_object *gem_obj;
 
-       mutex_lock(&drm->struct_mutex);
-
        gem_obj = drm_gem_object_lookup(drm, file_priv, handle);
        if (!gem_obj) {
                dev_err(drm->dev, "failed to lookup GEM object\n");
-               mutex_unlock(&drm->struct_mutex);
                return -EINVAL;
        }
 
        *offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
 
-       drm_gem_object_unreference(gem_obj);
-
-       mutex_unlock(&drm->struct_mutex);
+       drm_gem_object_unreference_unlocked(gem_obj);
 
        return 0;
 }
index 9fd784b8966b9743ff29ce5fa3defbf92b292caf..22d207e211e719b76b17c2a470d8323bb73ae6ba 100644 (file)
@@ -43,8 +43,8 @@
 #include <linux/export.h>
 
 /* Access macro for slots in vblank timestamp ringbuffer. */
-#define vblanktimestamp(dev, crtc, count) \
-       ((dev)->vblank[crtc].time[(count) % DRM_VBLANKTIME_RBSIZE])
+#define vblanktimestamp(dev, pipe, count) \
+       ((dev)->vblank[pipe].time[(count) % DRM_VBLANKTIME_RBSIZE])
 
 /* Retry timestamp calculation up to 3 times to satisfy
  * drm_timestamp_precision before giving up.
@@ -57,7 +57,7 @@
 #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
 
 static bool
-drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
+drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
                          struct timeval *tvblank, unsigned flags);
 
 static unsigned int drm_timestamp_precision = 20;  /* Default to 20 usecs. */
@@ -75,7 +75,7 @@ module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600)
 module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
 
 static void store_vblank(struct drm_device *dev, int crtc,
-                        unsigned vblank_count_inc,
+                        u32 vblank_count_inc,
                         struct timeval *t_vblank)
 {
        struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
@@ -107,7 +107,7 @@ static void store_vblank(struct drm_device *dev, int crtc,
 /**
  * drm_update_vblank_count - update the master vblank counter
  * @dev: DRM device
- * @crtc: counter to update
+ * @pipe: counter to update
  *
  * Call back into the driver to update the appropriate vblank counter
  * (specified by @crtc).  Deal with wraparound, if it occurred, and
@@ -120,9 +120,9 @@ static void store_vblank(struct drm_device *dev, int crtc,
  * Note: caller must hold dev->vbl_lock since this reads & writes
  * device vblank fields.
  */
-static void drm_update_vblank_count(struct drm_device *dev, int crtc)
+static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        u32 cur_vblank, diff;
        bool rc;
        struct timeval t_vblank;
@@ -140,21 +140,21 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
         * corresponding vblank timestamp.
         */
        do {
-               cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
-               rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0);
-       } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));
+               cur_vblank = dev->driver->get_vblank_counter(dev, pipe);
+               rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, 0);
+       } while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe));
 
        /* Deal with counter wrap */
        diff = cur_vblank - vblank->last;
        if (cur_vblank < vblank->last) {
                diff += dev->max_vblank_count + 1;
 
-               DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
-                         crtc, vblank->last, cur_vblank, diff);
+               DRM_DEBUG("last_vblank[%u]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
+                         pipe, vblank->last, cur_vblank, diff);
        }
 
-       DRM_DEBUG("updating vblank count on crtc %d, missed %d\n",
-                 crtc, diff);
+       DRM_DEBUG("updating vblank count on crtc %u, missed %d\n",
+                 pipe, diff);
 
        if (diff == 0)
                return;
@@ -167,7 +167,7 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
        if (!rc)
                t_vblank = (struct timeval) {0, 0};
 
-       store_vblank(dev, crtc, diff, &t_vblank);
+       store_vblank(dev, pipe, diff, &t_vblank);
 }
 
 /*
@@ -176,9 +176,9 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
  * are preserved, even if there are any spurious vblank irq's after
  * disable.
  */
-static void vblank_disable_and_save(struct drm_device *dev, int crtc)
+static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        unsigned long irqflags;
        u32 vblcount;
        s64 diff_ns;
@@ -206,8 +206,8 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
         * vblank interrupt is disabled.
         */
        if (!vblank->enabled &&
-           drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0)) {
-               drm_update_vblank_count(dev, crtc);
+           drm_get_last_vbltimestamp(dev, pipe, &tvblank, 0)) {
+               drm_update_vblank_count(dev, pipe);
                spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
                return;
        }
@@ -218,7 +218,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
         * hardware potentially runtime suspended.
         */
        if (vblank->enabled) {
-               dev->driver->disable_vblank(dev, crtc);
+               dev->driver->disable_vblank(dev, pipe);
                vblank->enabled = false;
        }
 
@@ -235,9 +235,9 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
         * delayed gpu counter increment.
         */
        do {
-               vblank->last = dev->driver->get_vblank_counter(dev, crtc);
-               vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0);
-       } while (vblank->last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc);
+               vblank->last = dev->driver->get_vblank_counter(dev, pipe);
+               vblrc = drm_get_last_vbltimestamp(dev, pipe, &tvblank, 0);
+       } while (vblank->last != dev->driver->get_vblank_counter(dev, pipe) && (--count) && vblrc);
 
        if (!count)
                vblrc = 0;
@@ -247,7 +247,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
         */
        vblcount = vblank->count;
        diff_ns = timeval_to_ns(&tvblank) -
-                 timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
+                 timeval_to_ns(&vblanktimestamp(dev, pipe, vblcount));
 
        /* If there is at least 1 msec difference between the last stored
         * timestamp and tvblank, then we are currently executing our
@@ -262,7 +262,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
         * hope for the best.
         */
        if (vblrc && (abs64(diff_ns) > 1000000))
-               store_vblank(dev, crtc, 1, &tvblank);
+               store_vblank(dev, pipe, 1, &tvblank);
 
        spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
 }
@@ -271,16 +271,16 @@ static void vblank_disable_fn(unsigned long arg)
 {
        struct drm_vblank_crtc *vblank = (void *)arg;
        struct drm_device *dev = vblank->dev;
+       unsigned int pipe = vblank->pipe;
        unsigned long irqflags;
-       int crtc = vblank->crtc;
 
        if (!dev->vblank_disable_allowed)
                return;
 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
        if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) {
-               DRM_DEBUG("disabling vblank on crtc %d\n", crtc);
-               vblank_disable_and_save(dev, crtc);
+               DRM_DEBUG("disabling vblank on crtc %u\n", pipe);
+               vblank_disable_and_save(dev, pipe);
        }
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 }
@@ -293,14 +293,14 @@ static void vblank_disable_fn(unsigned long arg)
  */
 void drm_vblank_cleanup(struct drm_device *dev)
 {
-       int crtc;
+       unsigned int pipe;
 
        /* Bail if the driver didn't call drm_vblank_init() */
        if (dev->num_crtcs == 0)
                return;
 
-       for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
-               struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       for (pipe = 0; pipe < dev->num_crtcs; pipe++) {
+               struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
 
                WARN_ON(vblank->enabled &&
                        drm_core_check_feature(dev, DRIVER_MODESET));
@@ -316,17 +316,18 @@ EXPORT_SYMBOL(drm_vblank_cleanup);
 
 /**
  * drm_vblank_init - initialize vblank support
- * @dev: drm_device
- * @num_crtcs: number of crtcs supported by @dev
+ * @dev: DRM device
+ * @num_crtcs: number of CRTCs supported by @dev
  *
  * This function initializes vblank support for @num_crtcs display pipelines.
  *
  * Returns:
  * Zero on success or a negative error code on failure.
  */
-int drm_vblank_init(struct drm_device *dev, int num_crtcs)
+int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs)
 {
-       int i, ret = -ENOMEM;
+       int ret = -ENOMEM;
+       unsigned int i;
 
        spin_lock_init(&dev->vbl_lock);
        spin_lock_init(&dev->vblank_time_lock);
@@ -341,7 +342,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
                struct drm_vblank_crtc *vblank = &dev->vblank[i];
 
                vblank->dev = dev;
-               vblank->crtc = i;
+               vblank->pipe = i;
                init_waitqueue_head(&vblank->queue);
                setup_timer(&vblank->disable_timer, vblank_disable_fn,
                            (unsigned long)vblank);
@@ -624,17 +625,17 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc,
                if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                        framedur_ns /= 2;
        } else
-               DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
+               DRM_ERROR("crtc %u: Can't calculate constants, dotclock = 0!\n",
                          crtc->base.id);
 
        crtc->pixeldur_ns = pixeldur_ns;
        crtc->linedur_ns  = linedur_ns;
        crtc->framedur_ns = framedur_ns;
 
-       DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
+       DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
                  crtc->base.id, mode->crtc_htotal,
                  mode->crtc_vtotal, mode->crtc_vdisplay);
-       DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
+       DRM_DEBUG("crtc %u: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
                  crtc->base.id, dotclock, framedur_ns,
                  linedur_ns, pixeldur_ns);
 }
@@ -643,7 +644,7 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
 /**
  * drm_calc_vbltimestamp_from_scanoutpos - precise vblank timestamp helper
  * @dev: DRM device
- * @crtc: Which CRTC's vblank timestamp to retrieve
+ * @pipe: index of CRTC whose vblank timestamp to retrieve
  * @max_error: Desired maximum allowable error in timestamps (nanosecs)
  *             On return contains true maximum error of timestamp
  * @vblank_time: Pointer to struct timeval which should receive the timestamp
@@ -686,7 +687,8 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
  * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.
  *
  */
-int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
+int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
+                                         unsigned int pipe,
                                          int *max_error,
                                          struct timeval *vblank_time,
                                          unsigned flags,
@@ -700,8 +702,8 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
        int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
        bool invbl;
 
-       if (crtc < 0 || crtc >= dev->num_crtcs) {
-               DRM_ERROR("Invalid crtc %d\n", crtc);
+       if (pipe >= dev->num_crtcs) {
+               DRM_ERROR("Invalid crtc %u\n", pipe);
                return -EINVAL;
        }
 
@@ -720,7 +722,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
         * Happens during initial modesetting of a crtc.
         */
        if (framedur_ns == 0) {
-               DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
+               DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe);
                return -EAGAIN;
        }
 
@@ -736,13 +738,13 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
                 * Get vertical and horizontal scanout position vpos, hpos,
                 * and bounding timestamps stime, etime, pre/post query.
                 */
-               vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos,
+               vbl_status = dev->driver->get_scanout_position(dev, pipe, flags, &vpos,
                                                               &hpos, &stime, &etime);
 
                /* Return as no-op if scanout query unsupported or failed. */
                if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
-                       DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n",
-                                 crtc, vbl_status);
+                       DRM_DEBUG("crtc %u : scanoutpos query failed [%d].\n",
+                                 pipe, vbl_status);
                        return -EIO;
                }
 
@@ -756,8 +758,8 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
 
        /* Noisy system timing? */
        if (i == DRM_TIMESTAMP_MAXRETRIES) {
-               DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n",
-                         crtc, duration_ns/1000, *max_error/1000, i);
+               DRM_DEBUG("crtc %u: Noisy timestamp %d us > %d us [%d reps].\n",
+                         pipe, duration_ns/1000, *max_error/1000, i);
        }
 
        /* Return upper bound of timestamp precision error. */
@@ -790,8 +792,8 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
                etime = ktime_sub_ns(etime, delta_ns);
        *vblank_time = ktime_to_timeval(etime);
 
-       DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
-                 crtc, (int)vbl_status, hpos, vpos,
+       DRM_DEBUG("crtc %u : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
+                 pipe, (int)vbl_status, hpos, vpos,
                  (long)tv_etime.tv_sec, (long)tv_etime.tv_usec,
                  (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
                  duration_ns/1000, i);
@@ -816,7 +818,7 @@ static struct timeval get_drm_timestamp(void)
  * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
  *                             vblank interval
  * @dev: DRM device
- * @crtc: which CRTC's vblank timestamp to retrieve
+ * @pipe: index of CRTC whose vblank timestamp to retrieve
  * @tvblank: Pointer to target struct timeval which should receive the timestamp
  * @flags: Flags to pass to driver:
  *         0 = Default,
@@ -833,7 +835,7 @@ static struct timeval get_drm_timestamp(void)
  * True if timestamp is considered to be very precise, false otherwise.
  */
 static bool
-drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
+drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
                          struct timeval *tvblank, unsigned flags)
 {
        int ret;
@@ -843,7 +845,7 @@ drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
 
        /* Query driver if possible and precision timestamping enabled. */
        if (dev->driver->get_vblank_timestamp && (max_error > 0)) {
-               ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error,
+               ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error,
                                                        tvblank, flags);
                if (ret > 0)
                        return true;
@@ -860,7 +862,7 @@ drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
 /**
  * drm_vblank_count - retrieve "cooked" vblank counter value
  * @dev: DRM device
- * @crtc: which counter to retrieve
+ * @pipe: index of CRTC for which to retrieve the counter
  *
  * Fetches the "cooked" vblank count value that represents the number of
  * vblank events since the system was booted, including lost events due to
@@ -871,12 +873,13 @@ drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
  * Returns:
  * The software vblank counter.
  */
-u32 drm_vblank_count(struct drm_device *dev, int crtc)
+u32 drm_vblank_count(struct drm_device *dev, int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
 
-       if (WARN_ON(crtc >= dev->num_crtcs))
+       if (WARN_ON(pipe >= dev->num_crtcs))
                return 0;
+
        return vblank->count;
 }
 EXPORT_SYMBOL(drm_vblank_count);
@@ -901,11 +904,10 @@ u32 drm_crtc_vblank_count(struct drm_crtc *crtc)
 EXPORT_SYMBOL(drm_crtc_vblank_count);
 
 /**
- * drm_vblank_count_and_time - retrieve "cooked" vblank counter value
- * and the system timestamp corresponding to that vblank counter value.
- *
+ * drm_vblank_count_and_time - retrieve "cooked" vblank counter value and the
+ *     system timestamp corresponding to that vblank counter value.
  * @dev: DRM device
- * @crtc: which counter to retrieve
+ * @pipe: index of CRTC whose counter to retrieve
  * @vblanktime: Pointer to struct timeval to receive the vblank timestamp.
  *
  * Fetches the "cooked" vblank count value that represents the number of
@@ -913,13 +915,13 @@ EXPORT_SYMBOL(drm_crtc_vblank_count);
  * modesetting activity. Returns corresponding system timestamp of the time
  * of the vblank interval that corresponds to the current vblank counter value.
  */
-u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
+u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe,
                              struct timeval *vblanktime)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        u32 cur_vblank;
 
-       if (WARN_ON(crtc >= dev->num_crtcs))
+       if (WARN_ON(pipe >= dev->num_crtcs))
                return 0;
 
        /*
@@ -930,7 +932,7 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
        do {
                cur_vblank = vblank->count;
                smp_rmb();
-               *vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
+               *vblanktime = vblanktimestamp(dev, pipe, cur_vblank);
                smp_rmb();
        } while (cur_vblank != vblank->count);
 
@@ -957,7 +959,7 @@ static void send_vblank_event(struct drm_device *dev,
 /**
  * drm_send_vblank_event - helper to send vblank event after pageflip
  * @dev: DRM device
- * @crtc: CRTC in question
+ * @pipe: CRTC index
  * @e: the event to send
  *
  * Updates sequence # and timestamp on event, and sends it to userspace.
@@ -965,20 +967,20 @@ static void send_vblank_event(struct drm_device *dev,
  *
  * This is the legacy version of drm_crtc_send_vblank_event().
  */
-void drm_send_vblank_event(struct drm_device *dev, int crtc,
-               struct drm_pending_vblank_event *e)
+void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe,
+                          struct drm_pending_vblank_event *e)
 {
        struct timeval now;
        unsigned int seq;
 
-       if (crtc >= 0) {
-               seq = drm_vblank_count_and_time(dev, crtc, &now);
+       if (dev->num_crtcs > 0) {
+               seq = drm_vblank_count_and_time(dev, pipe, &now);
        } else {
                seq = 0;
 
                now = get_drm_timestamp();
        }
-       e->pipe = crtc;
+       e->pipe = pipe;
        send_vblank_event(dev, e, seq, &now);
 }
 EXPORT_SYMBOL(drm_send_vblank_event);
@@ -1003,11 +1005,14 @@ EXPORT_SYMBOL(drm_crtc_send_vblank_event);
 /**
  * drm_vblank_enable - enable the vblank interrupt on a CRTC
  * @dev: DRM device
- * @crtc: CRTC in question
+ * @pipe: CRTC index
+ *
+ * Returns:
+ * Zero on success or a negative error code on failure.
  */
-static int drm_vblank_enable(struct drm_device *dev, int crtc)
+static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        int ret = 0;
 
        assert_spin_locked(&dev->vbl_lock);
@@ -1022,13 +1027,13 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc)
                 * timestamps. Filtercode in drm_handle_vblank() will
                 * prevent double-accounting of same vblank interval.
                 */
-               ret = dev->driver->enable_vblank(dev, crtc);
-               DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
+               ret = dev->driver->enable_vblank(dev, pipe);
+               DRM_DEBUG("enabling vblank on crtc %u, ret: %d\n", pipe, ret);
                if (ret)
                        atomic_dec(&vblank->refcount);
                else {
                        vblank->enabled = true;
-                       drm_update_vblank_count(dev, crtc);
+                       drm_update_vblank_count(dev, pipe);
                }
        }
 
@@ -1040,7 +1045,7 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc)
 /**
  * drm_vblank_get - get a reference count on vblank events
  * @dev: DRM device
- * @crtc: which CRTC to own
+ * @pipe: index of CRTC to own
  *
  * Acquire a reference count on vblank events to avoid having them disabled
  * while in use.
@@ -1048,24 +1053,24 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc)
  * This is the legacy version of drm_crtc_vblank_get().
  *
  * Returns:
- * Zero on success, nonzero on failure.
+ * Zero on success or a negative error code on failure.
  */
-int drm_vblank_get(struct drm_device *dev, int crtc)
+int drm_vblank_get(struct drm_device *dev, unsigned int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        unsigned long irqflags;
        int ret = 0;
 
        if (!dev->num_crtcs)
                return -EINVAL;
 
-       if (WARN_ON(crtc >= dev->num_crtcs))
+       if (WARN_ON(pipe >= dev->num_crtcs))
                return -EINVAL;
 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
        /* Going from 0->1 means we have to enable interrupts again */
        if (atomic_add_return(1, &vblank->refcount) == 1) {
-               ret = drm_vblank_enable(dev, crtc);
+               ret = drm_vblank_enable(dev, pipe);
        } else {
                if (!vblank->enabled) {
                        atomic_dec(&vblank->refcount);
@@ -1088,7 +1093,7 @@ EXPORT_SYMBOL(drm_vblank_get);
  * This is the native kms version of drm_vblank_get().
  *
  * Returns:
- * Zero on success, nonzero on failure.
+ * Zero on success or a negative error code on failure.
  */
 int drm_crtc_vblank_get(struct drm_crtc *crtc)
 {
@@ -1097,23 +1102,23 @@ int drm_crtc_vblank_get(struct drm_crtc *crtc)
 EXPORT_SYMBOL(drm_crtc_vblank_get);
 
 /**
- * drm_vblank_put - give up ownership of vblank events
+ * drm_vblank_put - release ownership of vblank events
  * @dev: DRM device
- * @crtc: which counter to give up
+ * @pipe: index of CRTC to release
  *
  * Release ownership of a given vblank counter, turning off interrupts
  * if possible. Disable interrupts after drm_vblank_offdelay milliseconds.
  *
  * This is the legacy version of drm_crtc_vblank_put().
  */
-void drm_vblank_put(struct drm_device *dev, int crtc)
+void drm_vblank_put(struct drm_device *dev, unsigned int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
 
-       if (WARN_ON(atomic_read(&vblank->refcount) == 0))
+       if (WARN_ON(pipe >= dev->num_crtcs))
                return;
 
-       if (WARN_ON(crtc >= dev->num_crtcs))
+       if (WARN_ON(atomic_read(&vblank->refcount) == 0))
                return;
 
        /* Last user schedules interrupt disable */
@@ -1147,30 +1152,34 @@ EXPORT_SYMBOL(drm_crtc_vblank_put);
 /**
  * drm_wait_one_vblank - wait for one vblank
  * @dev: DRM device
- * @crtc: crtc index
+ * @pipe: CRTC index
  *
  * This waits for one vblank to pass on @crtc, using the irq driver interfaces.
  * It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
  * due to lack of driver support or because the crtc is off.
  */
-void drm_wait_one_vblank(struct drm_device *dev, int crtc)
+void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        int ret;
        u32 last;
 
-       ret = drm_vblank_get(dev, crtc);
-       if (WARN(ret, "vblank not available on crtc %i, ret=%i\n", crtc, ret))
+       if (WARN_ON(pipe >= dev->num_crtcs))
                return;
 
-       last = drm_vblank_count(dev, crtc);
+       ret = drm_vblank_get(dev, pipe);
+       if (WARN(ret, "vblank not available on crtc %i, ret=%i\n", pipe, ret))
+               return;
 
-       ret = wait_event_timeout(dev->vblank[crtc].queue,
-                                last != drm_vblank_count(dev, crtc),
+       last = drm_vblank_count(dev, pipe);
+
+       ret = wait_event_timeout(vblank->queue,
+                                last != drm_vblank_count(dev, pipe),
                                 msecs_to_jiffies(100));
 
-       WARN(ret == 0, "vblank wait timed out on crtc %i\n", crtc);
+       WARN(ret == 0, "vblank wait timed out on crtc %i\n", pipe);
 
-       drm_vblank_put(dev, crtc);
+       drm_vblank_put(dev, pipe);
 }
 EXPORT_SYMBOL(drm_wait_one_vblank);
 
@@ -1191,7 +1200,7 @@ EXPORT_SYMBOL(drm_crtc_wait_one_vblank);
 /**
  * drm_vblank_off - disable vblank events on a CRTC
  * @dev: DRM device
- * @crtc: CRTC in question
+ * @pipe: CRTC index
  *
  * Drivers can use this function to shut down the vblank interrupt handling when
  * disabling a crtc. This function ensures that the latest vblank frame count is
@@ -1202,21 +1211,21 @@ EXPORT_SYMBOL(drm_crtc_wait_one_vblank);
  *
  * This is the legacy version of drm_crtc_vblank_off().
  */
-void drm_vblank_off(struct drm_device *dev, int crtc)
+void drm_vblank_off(struct drm_device *dev, unsigned int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        struct drm_pending_vblank_event *e, *t;
        struct timeval now;
        unsigned long irqflags;
        unsigned int seq;
 
-       if (WARN_ON(crtc >= dev->num_crtcs))
+       if (WARN_ON(pipe >= dev->num_crtcs))
                return;
 
        spin_lock_irqsave(&dev->event_lock, irqflags);
 
        spin_lock(&dev->vbl_lock);
-       vblank_disable_and_save(dev, crtc);
+       vblank_disable_and_save(dev, pipe);
        wake_up(&vblank->queue);
 
        /*
@@ -1230,16 +1239,16 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
        spin_unlock(&dev->vbl_lock);
 
        /* Send any queued vblank events, lest the natives grow disquiet */
-       seq = drm_vblank_count_and_time(dev, crtc, &now);
+       seq = drm_vblank_count_and_time(dev, pipe, &now);
 
        list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
-               if (e->pipe != crtc)
+               if (e->pipe != pipe)
                        continue;
                DRM_DEBUG("Sending premature vblank event on disable: \
                          wanted %d, current %d\n",
                          e->event.sequence, seq);
                list_del(&e->base.link);
-               drm_vblank_put(dev, e->pipe);
+               drm_vblank_put(dev, pipe);
                send_vblank_event(dev, e, seq, &now);
        }
        spin_unlock_irqrestore(&dev->event_lock, irqflags);
@@ -1300,7 +1309,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_reset);
 /**
  * drm_vblank_on - enable vblank events on a CRTC
  * @dev: DRM device
- * @crtc: CRTC in question
+ * @pipe: CRTC index
  *
  * This functions restores the vblank interrupt state captured with
  * drm_vblank_off() again. Note that calls to drm_vblank_on() and
@@ -1309,12 +1318,12 @@ EXPORT_SYMBOL(drm_crtc_vblank_reset);
  *
  * This is the legacy version of drm_crtc_vblank_on().
  */
-void drm_vblank_on(struct drm_device *dev, int crtc)
+void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        unsigned long irqflags;
 
-       if (WARN_ON(crtc >= dev->num_crtcs))
+       if (WARN_ON(pipe >= dev->num_crtcs))
                return;
 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -1332,7 +1341,7 @@ void drm_vblank_on(struct drm_device *dev, int crtc)
         * vblank counter value before and after a modeset
         */
        vblank->last =
-               (dev->driver->get_vblank_counter(dev, crtc) - 1) &
+               (dev->driver->get_vblank_counter(dev, pipe) - 1) &
                dev->max_vblank_count;
        /*
         * re-enable interrupts if there are users left, or the
@@ -1340,7 +1349,7 @@ void drm_vblank_on(struct drm_device *dev, int crtc)
         */
        if (atomic_read(&vblank->refcount) != 0 ||
            (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0))
-               WARN_ON(drm_vblank_enable(dev, crtc));
+               WARN_ON(drm_vblank_enable(dev, pipe));
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 }
 EXPORT_SYMBOL(drm_vblank_on);
@@ -1365,7 +1374,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_on);
 /**
  * drm_vblank_pre_modeset - account for vblanks across mode sets
  * @dev: DRM device
- * @crtc: CRTC in question
+ * @pipe: CRTC index
  *
  * Account for vblank events across mode setting events, which will likely
  * reset the hardware frame counter.
@@ -1385,15 +1394,15 @@ EXPORT_SYMBOL(drm_crtc_vblank_on);
  * Drivers must call drm_vblank_post_modeset() when re-enabling the same crtc
  * again.
  */
-void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
+void drm_vblank_pre_modeset(struct drm_device *dev, unsigned int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
 
        /* vblank is not initialized (IRQ not installed ?), or has been freed */
        if (!dev->num_crtcs)
                return;
 
-       if (WARN_ON(crtc >= dev->num_crtcs))
+       if (WARN_ON(pipe >= dev->num_crtcs))
                return;
 
        /*
@@ -1405,7 +1414,7 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
         */
        if (!vblank->inmodeset) {
                vblank->inmodeset = 0x1;
-               if (drm_vblank_get(dev, crtc) == 0)
+               if (drm_vblank_get(dev, pipe) == 0)
                        vblank->inmodeset |= 0x2;
        }
 }
@@ -1414,27 +1423,30 @@ EXPORT_SYMBOL(drm_vblank_pre_modeset);
 /**
  * drm_vblank_post_modeset - undo drm_vblank_pre_modeset changes
  * @dev: DRM device
- * @crtc: CRTC in question
+ * @pipe: CRTC index
  *
  * This function again drops the temporary vblank reference acquired in
  * drm_vblank_pre_modeset.
  */
-void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
+void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        unsigned long irqflags;
 
        /* vblank is not initialized (IRQ not installed ?), or has been freed */
        if (!dev->num_crtcs)
                return;
 
+       if (WARN_ON(pipe >= dev->num_crtcs))
+               return;
+
        if (vblank->inmodeset) {
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
                dev->vblank_disable_allowed = true;
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
                if (vblank->inmodeset & 0x2)
-                       drm_vblank_put(dev, crtc);
+                       drm_vblank_put(dev, pipe);
 
                vblank->inmodeset = 0;
        }
@@ -1456,7 +1468,7 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        struct drm_modeset_ctl *modeset = data;
-       unsigned int crtc;
+       unsigned int pipe;
 
        /* If drm_vblank_init() hasn't been called yet, just no-op */
        if (!dev->num_crtcs)
@@ -1466,16 +1478,16 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return 0;
 
-       crtc = modeset->crtc;
-       if (crtc >= dev->num_crtcs)
+       pipe = modeset->crtc;
+       if (pipe >= dev->num_crtcs)
                return -EINVAL;
 
        switch (modeset->cmd) {
        case _DRM_PRE_MODESET:
-               drm_vblank_pre_modeset(dev, crtc);
+               drm_vblank_pre_modeset(dev, pipe);
                break;
        case _DRM_POST_MODESET:
-               drm_vblank_post_modeset(dev, crtc);
+               drm_vblank_post_modeset(dev, pipe);
                break;
        default:
                return -EINVAL;
@@ -1484,7 +1496,7 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
        return 0;
 }
 
-static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
+static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
                                  union drm_wait_vblank *vblwait,
                                  struct drm_file *file_priv)
 {
@@ -1538,7 +1550,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
                vblwait->reply.sequence = vblwait->request.sequence;
        }
 
-       DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
+       DRM_DEBUG("event on vblank count %d, current %d, crtc %u\n",
                  vblwait->request.sequence, seq, pipe);
 
        trace_drm_vblank_event_queued(current->pid, pipe,
@@ -1587,7 +1599,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
        struct drm_vblank_crtc *vblank;
        union drm_wait_vblank *vblwait = data;
        int ret;
-       unsigned int flags, seq, crtc, high_crtc;
+       unsigned int flags, seq, pipe, high_pipe;
 
        if (!dev->irq_enabled)
                return -EINVAL;
@@ -1606,22 +1618,22 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
        }
 
        flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
-       high_crtc = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK);
-       if (high_crtc)
-               crtc = high_crtc >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
+       high_pipe = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK);
+       if (high_pipe)
+               pipe = high_pipe >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
        else
-               crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
-       if (crtc >= dev->num_crtcs)
+               pipe = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
+       if (pipe >= dev->num_crtcs)
                return -EINVAL;
 
-       vblank = &dev->vblank[crtc];
+       vblank = &dev->vblank[pipe];
 
-       ret = drm_vblank_get(dev, crtc);
+       ret = drm_vblank_get(dev, pipe);
        if (ret) {
                DRM_DEBUG("failed to acquire vblank counter, %d\n", ret);
                return ret;
        }
-       seq = drm_vblank_count(dev, crtc);
+       seq = drm_vblank_count(dev, pipe);
 
        switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
        case _DRM_VBLANK_RELATIVE:
@@ -1638,7 +1650,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
                /* must hold on to the vblank ref until the event fires
                 * drm_vblank_put will be called asynchronously
                 */
-               return drm_queue_vblank_event(dev, crtc, vblwait, file_priv);
+               return drm_queue_vblank_event(dev, pipe, vblwait, file_priv);
        }
 
        if ((flags & _DRM_VBLANK_NEXTONMISS) &&
@@ -1646,11 +1658,11 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
                vblwait->request.sequence = seq + 1;
        }
 
-       DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
-                 vblwait->request.sequence, crtc);
+       DRM_DEBUG("waiting on vblank count %d, crtc %u\n",
+                 vblwait->request.sequence, pipe);
        vblank->last_wait = vblwait->request.sequence;
        DRM_WAIT_ON(ret, vblank->queue, 3 * HZ,
-                   (((drm_vblank_count(dev, crtc) -
+                   (((drm_vblank_count(dev, pipe) -
                       vblwait->request.sequence) <= (1 << 23)) ||
                     !vblank->enabled ||
                     !dev->irq_enabled));
@@ -1658,7 +1670,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
        if (ret != -EINTR) {
                struct timeval now;
 
-               vblwait->reply.sequence = drm_vblank_count_and_time(dev, crtc, &now);
+               vblwait->reply.sequence = drm_vblank_count_and_time(dev, pipe, &now);
                vblwait->reply.tval_sec = now.tv_sec;
                vblwait->reply.tval_usec = now.tv_usec;
 
@@ -1669,11 +1681,11 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
        }
 
 done:
-       drm_vblank_put(dev, crtc);
+       drm_vblank_put(dev, pipe);
        return ret;
 }
 
-static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
+static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe)
 {
        struct drm_pending_vblank_event *e, *t;
        struct timeval now;
@@ -1681,10 +1693,10 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
 
        assert_spin_locked(&dev->event_lock);
 
-       seq = drm_vblank_count_and_time(dev, crtc, &now);
+       seq = drm_vblank_count_and_time(dev, pipe, &now);
 
        list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
-               if (e->pipe != crtc)
+               if (e->pipe != pipe)
                        continue;
                if ((seq - e->event.sequence) > (1<<23))
                        continue;
@@ -1693,26 +1705,26 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
                          e->event.sequence, seq);
 
                list_del(&e->base.link);
-               drm_vblank_put(dev, e->pipe);
+               drm_vblank_put(dev, pipe);
                send_vblank_event(dev, e, seq, &now);
        }
 
-       trace_drm_vblank_event(crtc, seq);
+       trace_drm_vblank_event(pipe, seq);
 }
 
 /**
  * drm_handle_vblank - handle a vblank event
  * @dev: DRM device
- * @crtc: where this event occurred
+ * @pipe: index of CRTC where this event occurred
  *
  * Drivers should call this routine in their vblank interrupt handlers to
  * update the vblank counter and send any signals that may be pending.
  *
  * This is the legacy version of drm_crtc_handle_vblank().
  */
-bool drm_handle_vblank(struct drm_device *dev, int crtc)
+bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe)
 {
-       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        u32 vblcount;
        s64 diff_ns;
        struct timeval tvblank;
@@ -1721,7 +1733,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
        if (WARN_ON_ONCE(!dev->num_crtcs))
                return false;
 
-       if (WARN_ON(crtc >= dev->num_crtcs))
+       if (WARN_ON(pipe >= dev->num_crtcs))
                return false;
 
        spin_lock_irqsave(&dev->event_lock, irqflags);
@@ -1745,11 +1757,11 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
 
        /* Get current timestamp and count. */
        vblcount = vblank->count;
-       drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);
+       drm_get_last_vbltimestamp(dev, pipe, &tvblank, DRM_CALLED_FROM_VBLIRQ);
 
        /* Compute time difference to timestamp of last vblank */
        diff_ns = timeval_to_ns(&tvblank) -
-                 timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
+                 timeval_to_ns(&vblanktimestamp(dev, pipe, vblcount));
 
        /* Update vblank timestamp and count if at least
         * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds
@@ -1761,15 +1773,15 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
         * ignore those for accounting.
         */
        if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS)
-               store_vblank(dev, crtc, 1, &tvblank);
+               store_vblank(dev, pipe, 1, &tvblank);
        else
-               DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
-                         crtc, (int) diff_ns);
+               DRM_DEBUG("crtc %u: Redundant vblirq ignored. diff_ns = %d\n",
+                         pipe, (int) diff_ns);
 
        spin_unlock(&dev->vblank_time_lock);
 
        wake_up(&vblank->queue);
-       drm_handle_vblank_events(dev, crtc);
+       drm_handle_vblank_events(dev, pipe);
 
        spin_unlock_irqrestore(&dev->event_lock, irqflags);
 
index 744dfbc6a329aef96dfcab631c2f55fae61de7db..fba321ca434485d0f6f6d7898c84711eea47a577 100644 (file)
  *     drm_modeset_acquire_fini(&ctx);
  */
 
-
 /**
- * __drm_modeset_lock_all - internal helper to grab all modeset locks
- * @dev: DRM device
- * @trylock: trylock mode for atomic contexts
- *
- * This is a special version of drm_modeset_lock_all() which can also be used in
- * atomic contexts. Then @trylock must be set to true.
+ * drm_modeset_lock_all - take all modeset locks
+ * @dev: drm device
  *
- * Returns:
- * 0 on success or negative error code on failure.
+ * This function takes all modeset locks, suitable where a more fine-grained
+ * scheme isn't (yet) implemented. Locks must be dropped with
+ * drm_modeset_unlock_all.
  */
-int __drm_modeset_lock_all(struct drm_device *dev,
-                          bool trylock)
+void drm_modeset_lock_all(struct drm_device *dev)
 {
        struct drm_mode_config *config = &dev->mode_config;
        struct drm_modeset_acquire_ctx *ctx;
        int ret;
 
-       ctx = kzalloc(sizeof(*ctx),
-                     trylock ? GFP_ATOMIC : GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (WARN_ON(!ctx))
+               return;
 
-       if (trylock) {
-               if (!mutex_trylock(&config->mutex)) {
-                       ret = -EBUSY;
-                       goto out;
-               }
-       } else {
-               mutex_lock(&config->mutex);
-       }
+       mutex_lock(&config->mutex);
 
        drm_modeset_acquire_init(ctx, 0);
-       ctx->trylock_only = trylock;
 
 retry:
        ret = drm_modeset_lock(&config->connection_mutex, ctx);
@@ -108,7 +94,7 @@ retry:
 
        drm_warn_on_modeset_not_all_locked(dev);
 
-       return 0;
+       return;
 
 fail:
        if (ret == -EDEADLK) {
@@ -116,23 +102,7 @@ fail:
                goto retry;
        }
 
-out:
        kfree(ctx);
-       return ret;
-}
-EXPORT_SYMBOL(__drm_modeset_lock_all);
-
-/**
- * drm_modeset_lock_all - take all modeset locks
- * @dev: drm device
- *
- * This function takes all modeset locks, suitable where a more fine-grained
- * scheme isn't (yet) implemented. Locks must be dropped with
- * drm_modeset_unlock_all.
- */
-void drm_modeset_lock_all(struct drm_device *dev)
-{
-       WARN_ON(__drm_modeset_lock_all(dev, false) != 0);
 }
 EXPORT_SYMBOL(drm_modeset_lock_all);
 
index 46c7045733061e13c169d1c632fa80d82853c42a..5e5a07af02c85c4297df213847759bd620a82390 100644 (file)
@@ -437,7 +437,7 @@ int drm_plane_helper_commit(struct drm_plane *plane,
 
        for (i = 0; i < 2; i++) {
                if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
-                       crtc_funcs[i]->atomic_begin(crtc[i]);
+                       crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state);
        }
 
        /*
@@ -452,7 +452,7 @@ int drm_plane_helper_commit(struct drm_plane *plane,
 
        for (i = 0; i < 2; i++) {
                if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
-                       crtc_funcs[i]->atomic_flush(crtc[i]);
+                       crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state);
        }
 
        /*
index 43003c4ad80ba624d64d2ddd53e8b91534cb0952..df0b61a60501c46ac6a58da5ae0ec993cbb7f9f4 100644 (file)
@@ -56,7 +56,7 @@ config DRM_EXYNOS_DSI
 
 config DRM_EXYNOS_DP
        bool "EXYNOS DRM DP driver support"
-       depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
+       depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
        default DRM_EXYNOS
        select DRM_PANEL
        help
index 7de0b1084fcd31e362a5fdeca6f1ecd20a07f720..02aecfed6354b7518a8dee7eb7fb28436112f197 100644 (file)
@@ -3,10 +3,9 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
-exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \
-               exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \
-               exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
-               exynos_drm_plane.o exynos_drm_dmabuf.o
+exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fbdev.o \
+               exynos_drm_fb.o exynos_drm_gem.o exynos_drm_core.o \
+               exynos_drm_plane.o
 
 exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)    += exynos_drm_fimd.o
index 8b1225f245fc430b2bb6fd07e15bb77173a55483..484e312e0a22d58908ca1cf3a2183d7f7ce35467 100644 (file)
@@ -152,15 +152,15 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
 #define OFFSIZE(x)             (((x) & 0x3fff) << 14)
 #define PAGEWIDTH(x)           ((x) & 0x3fff)
 
-static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
+static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
+                                struct drm_framebuffer *fb)
 {
-       struct exynos_drm_plane *plane = &ctx->planes[win];
        unsigned long val;
 
        val = readl(ctx->addr + DECON_WINCONx(win));
        val &= ~WINCONx_BPPMODE_MASK;
 
-       switch (plane->pixel_format) {
+       switch (fb->pixel_format) {
        case DRM_FORMAT_XRGB1555:
                val |= WINCONx_BPPMODE_16BPP_I1555;
                val |= WINCONx_HAWSWP_F;
@@ -186,7 +186,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
                return;
        }
 
-       DRM_DEBUG_KMS("bpp = %u\n", plane->bpp);
+       DRM_DEBUG_KMS("bpp = %u\n", fb->bits_per_pixel);
 
        /*
         * In case of exynos, setting dma-burst to 16Word causes permanent
@@ -196,7 +196,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
         * movement causes unstable DMA which results into iommu crash/tear.
         */
 
-       if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+       if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
                val &= ~WINCONx_BURSTLEN_MASK;
                val |= WINCONx_BURSTLEN_8WORD;
        }
@@ -219,17 +219,16 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win,
        writel(val, ctx->addr + DECON_SHADOWCON);
 }
 
-static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
+static void decon_update_plane(struct exynos_drm_crtc *crtc,
+                              struct exynos_drm_plane *plane)
 {
        struct decon_context *ctx = crtc->ctx;
-       struct exynos_drm_plane *plane;
+       struct drm_plane_state *state = plane->base.state;
+       unsigned int win = plane->zpos;
+       unsigned int bpp = state->fb->bits_per_pixel >> 3;
+       unsigned int pitch = state->fb->pitches[0];
        u32 val;
 
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-       plane = &ctx->planes[win];
-
        if (ctx->suspended)
                return;
 
@@ -238,8 +237,8 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
        val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y);
        writel(val, ctx->addr + DECON_VIDOSDxA(win));
 
-       val = COORDINATE_X(plane->crtc_x + plane->crtc_width - 1) |
-               COORDINATE_Y(plane->crtc_y + plane->crtc_height - 1);
+       val = COORDINATE_X(plane->crtc_x + plane->crtc_w - 1) |
+               COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1);
        writel(val, ctx->addr + DECON_VIDOSDxB(win));
 
        val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
@@ -252,14 +251,14 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
 
        writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win));
 
-       val = plane->dma_addr[0] + plane->pitch * plane->crtc_height;
+       val = plane->dma_addr[0] + pitch * plane->crtc_h;
        writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
 
-       val = OFFSIZE(plane->pitch - plane->crtc_width * (plane->bpp >> 3))
-               | PAGEWIDTH(plane->crtc_width * (plane->bpp >> 3));
+       val = OFFSIZE(pitch - plane->crtc_w * bpp)
+               | PAGEWIDTH(plane->crtc_w * bpp);
        writel(val, ctx->addr + DECON_VIDW0xADD2(win));
 
-       decon_win_set_pixfmt(ctx, win);
+       decon_win_set_pixfmt(ctx, win, state->fb);
 
        /* window enable */
        val = readl(ctx->addr + DECON_WINCONx(win));
@@ -277,17 +276,13 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
                atomic_set(&ctx->win_updated, 1);
 }
 
-static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
+static void decon_disable_plane(struct exynos_drm_crtc *crtc,
+                               struct exynos_drm_plane *plane)
 {
        struct decon_context *ctx = crtc->ctx;
-       struct exynos_drm_plane *plane;
+       unsigned int win = plane->zpos;
        u32 val;
 
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-       plane = &ctx->planes[win];
-
        if (ctx->suspended)
                return;
 
@@ -378,7 +373,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
         * a destroyed buffer later.
         */
        for (i = 0; i < WINDOWS_NR; i++)
-               decon_win_disable(crtc, i);
+               decon_disable_plane(crtc, &ctx->planes[i]);
 
        decon_swreset(ctx);
 
@@ -407,7 +402,7 @@ void decon_te_irq_handler(struct exynos_drm_crtc *crtc)
                writel(val, ctx->addr + DECON_TRIGCON);
        }
 
-       drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+       drm_crtc_handle_vblank(&ctx->crtc->base);
 }
 
 static void decon_clear_channels(struct exynos_drm_crtc *crtc)
@@ -460,10 +455,9 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = {
        .enable_vblank          = decon_enable_vblank,
        .disable_vblank         = decon_disable_vblank,
        .commit                 = decon_commit,
-       .win_commit             = decon_win_commit,
-       .win_disable            = decon_win_disable,
+       .update_plane           = decon_update_plane,
+       .disable_plane          = decon_disable_plane,
        .te_handler             = decon_te_irq_handler,
-       .clear_channels         = decon_clear_channels,
 };
 
 static int decon_bind(struct device *dev, struct device *master, void *data)
@@ -497,7 +491,9 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
                goto err;
        }
 
-       ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev);
+       decon_clear_channels(ctx->crtc);
+
+       ret = drm_iommu_attach_device(drm_dev, dev);
        if (ret)
                goto err;
 
@@ -514,8 +510,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data)
        decon_disable(ctx->crtc);
 
        /* detach this sub driver from iommu mapping if supported. */
-       if (is_drm_iommu_supported(ctx->drm_dev))
-               drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
+       drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
 }
 
 static const struct component_ops decon_component_ops = {
@@ -533,7 +528,7 @@ static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id)
 
        val = readl(ctx->addr + DECON_VIDINTCON1);
        if (val & VIDINTCON1_INTFRMPEND) {
-               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+               drm_crtc_handle_vblank(&ctx->crtc->base);
 
                /* clear */
                writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1);
@@ -553,7 +548,7 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
 
        val = readl(ctx->addr + DECON_VIDINTCON1);
        if (val & VIDINTCON1_INTFRMDONEPEND) {
-               exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+               exynos_drm_crtc_finish_pageflip(ctx->crtc);
 
                /* clear */
                writel(VIDINTCON1_INTFRMDONEPEND,
index 362532afd1a527e90df579fce5a4b3225419761b..07926547c94ff733090db523a2cb0be2ffa7e150 100644 (file)
@@ -61,7 +61,7 @@ struct decon_context {
        atomic_t                        wait_vsync_event;
 
        struct exynos_drm_panel_info panel;
-       struct exynos_drm_display *display;
+       struct drm_encoder *encoder;
 };
 
 static const struct of_device_id decon_driver_dt_match[] = {
@@ -126,7 +126,9 @@ static int decon_ctx_initialize(struct decon_context *ctx,
        ctx->drm_dev = drm_dev;
        ctx->pipe = priv->pipe++;
 
-       ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, ctx->dev);
+       decon_clear_channels(ctx->crtc);
+
+       ret = drm_iommu_attach_device(drm_dev, ctx->dev);
        if (ret)
                priv->pipe--;
 
@@ -136,8 +138,7 @@ static int decon_ctx_initialize(struct decon_context *ctx,
 static void decon_ctx_remove(struct decon_context *ctx)
 {
        /* detach this sub driver from iommu mapping if supported. */
-       if (is_drm_iommu_supported(ctx->drm_dev))
-               drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
+       drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
 }
 
 static u32 decon_calc_clkdiv(struct decon_context *ctx,
@@ -271,16 +272,16 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
        }
 }
 
-static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
+static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
+                                struct drm_framebuffer *fb)
 {
-       struct exynos_drm_plane *plane = &ctx->planes[win];
        unsigned long val;
        int padding;
 
        val = readl(ctx->regs + WINCON(win));
        val &= ~WINCONx_BPPMODE_MASK;
 
-       switch (plane->pixel_format) {
+       switch (fb->pixel_format) {
        case DRM_FORMAT_RGB565:
                val |= WINCONx_BPPMODE_16BPP_565;
                val |= WINCONx_BURSTLEN_16WORD;
@@ -329,7 +330,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
                break;
        }
 
-       DRM_DEBUG_KMS("bpp = %d\n", plane->bpp);
+       DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel);
 
        /*
         * In case of exynos, setting dma-burst to 16Word causes permanent
@@ -339,8 +340,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
         * movement causes unstable DMA which results into iommu crash/tear.
         */
 
-       padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
-       if (plane->fb_width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+       padding = (fb->pitches[0] / (fb->bits_per_pixel >> 3)) - fb->width;
+       if (fb->width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) {
                val &= ~WINCONx_BURSTLEN_MASK;
                val |= WINCONx_BURSTLEN_8WORD;
        }
@@ -382,23 +383,19 @@ 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, unsigned int win)
+static void decon_update_plane(struct exynos_drm_crtc *crtc,
+                              struct exynos_drm_plane *plane)
 {
        struct decon_context *ctx = crtc->ctx;
        struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
-       struct exynos_drm_plane *plane;
+       struct drm_plane_state *state = plane->base.state;
        int padding;
        unsigned long val, alpha;
        unsigned int last_x;
        unsigned int last_y;
-
-       if (ctx->suspended)
-               return;
-
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-       plane = &ctx->planes[win];
+       unsigned int win = plane->zpos;
+       unsigned int bpp = state->fb->bits_per_pixel >> 3;
+       unsigned int pitch = state->fb->pitches[0];
 
        if (ctx->suspended)
                return;
@@ -420,11 +417,11 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
        val = (unsigned long)plane->dma_addr[0];
        writel(val, ctx->regs + VIDW_BUF_START(win));
 
-       padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
+       padding = (pitch / bpp) - state->fb->width;
 
        /* buffer size */
-       writel(plane->fb_width + padding, ctx->regs + VIDW_WHOLE_X(win));
-       writel(plane->fb_height, ctx->regs + VIDW_WHOLE_Y(win));
+       writel(state->fb->width + padding, ctx->regs + VIDW_WHOLE_X(win));
+       writel(state->fb->height, ctx->regs + VIDW_WHOLE_Y(win));
 
        /* offset from the start of the buffer to read */
        writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win));
@@ -433,25 +430,25 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
        DRM_DEBUG_KMS("start addr = 0x%lx\n",
                        (unsigned long)val);
        DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       plane->crtc_width, plane->crtc_height);
+                       plane->crtc_w, plane->crtc_h);
 
        /*
         * OSD position.
         * In case the window layout goes of LCD layout, DECON fails.
         */
-       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;
+       if ((plane->crtc_x + plane->crtc_w) > mode->hdisplay)
+               plane->crtc_x = mode->hdisplay - plane->crtc_w;
+       if ((plane->crtc_y + plane->crtc_h) > mode->vdisplay)
+               plane->crtc_y = mode->vdisplay - plane->crtc_h;
 
        val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) |
                VIDOSDxA_TOPLEFT_Y(plane->crtc_y);
        writel(val, ctx->regs + VIDOSD_A(win));
 
-       last_x = plane->crtc_x + plane->crtc_width;
+       last_x = plane->crtc_x + plane->crtc_w;
        if (last_x)
                last_x--;
-       last_y = plane->crtc_y + plane->crtc_height;
+       last_y = plane->crtc_y + plane->crtc_h;
        if (last_y)
                last_y--;
 
@@ -475,7 +472,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
 
        writel(alpha, ctx->regs + VIDOSD_D(win));
 
-       decon_win_set_pixfmt(ctx, win);
+       decon_win_set_pixfmt(ctx, win, state->fb);
 
        /* hardware window 0 doesn't support color key. */
        if (win != 0)
@@ -495,17 +492,13 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
        writel(val, ctx->regs + DECON_UPDATE);
 }
 
-static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
+static void decon_disable_plane(struct exynos_drm_crtc *crtc,
+                               struct exynos_drm_plane *plane)
 {
        struct decon_context *ctx = crtc->ctx;
-       struct exynos_drm_plane *plane;
+       unsigned int win = plane->zpos;
        u32 val;
 
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-       plane = &ctx->planes[win];
-
        if (ctx->suspended)
                return;
 
@@ -601,7 +594,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
         * a destroyed buffer later.
         */
        for (i = 0; i < WINDOWS_NR; i++)
-               decon_win_disable(crtc, i);
+               decon_disable_plane(crtc, &ctx->planes[i]);
 
        clk_disable_unprepare(ctx->vclk);
        clk_disable_unprepare(ctx->eclk);
@@ -621,9 +614,8 @@ static const 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_commit = decon_win_commit,
-       .win_disable = decon_win_disable,
-       .clear_channels = decon_clear_channels,
+       .update_plane = decon_update_plane,
+       .disable_plane = decon_disable_plane,
 };
 
 
@@ -643,8 +635,8 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
                goto out;
 
        if (!ctx->i80_if) {
-               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
-               exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+               drm_crtc_handle_vblank(&ctx->crtc->base);
+               exynos_drm_crtc_finish_pageflip(ctx->crtc);
 
                /* set wait vsync event to zero and wake up queue. */
                if (atomic_read(&ctx->wait_vsync_event)) {
@@ -689,8 +681,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
                return PTR_ERR(ctx->crtc);
        }
 
-       if (ctx->display)
-               exynos_drm_create_enc_conn(drm_dev, ctx->display);
+       if (ctx->encoder)
+               exynos_dpi_bind(drm_dev, ctx->encoder);
 
        return 0;
 
@@ -703,8 +695,8 @@ static void decon_unbind(struct device *dev, struct device *master,
 
        decon_disable(ctx->crtc);
 
-       if (ctx->display)
-               exynos_dpi_remove(ctx->display);
+       if (ctx->encoder)
+               exynos_dpi_remove(ctx->encoder);
 
        decon_ctx_remove(ctx);
 }
@@ -789,9 +781,9 @@ static int decon_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ctx);
 
-       ctx->display = exynos_dpi_probe(dev);
-       if (IS_ERR(ctx->display)) {
-               ret = PTR_ERR(ctx->display);
+       ctx->encoder = exynos_dpi_probe(dev);
+       if (IS_ERR(ctx->encoder)) {
+               ret = PTR_ERR(ctx->encoder);
                goto err_iounmap;
        }
 
index 172b8002a2c824e3a373079cdf86a3098fecb206..d66ade0efac892b84ce7e26c4f9e132870806d33 100644 (file)
 #include <drm/drm_panel.h>
 
 #include "exynos_dp_core.h"
+#include "exynos_drm_crtc.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);
+       return to_exynos_crtc(dp->encoder.crtc);
 }
 
-static inline struct exynos_dp_device *
-display_to_dp(struct exynos_drm_display *d)
+static inline struct exynos_dp_device *encoder_to_dp(
+                                               struct drm_encoder *e)
 {
-       return container_of(d, struct exynos_dp_device, display);
+       return container_of(e, struct exynos_dp_device, encoder);
 }
 
 struct bridge_init {
@@ -795,9 +796,6 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp)
        /* Configure video slave mode */
        exynos_dp_enable_video_master(dp, 0);
 
-       /* Enable video */
-       exynos_dp_start_video(dp);
-
        timeout_loop = 0;
 
        for (;;) {
@@ -891,9 +889,9 @@ static void exynos_dp_hotplug(struct work_struct *work)
                drm_helper_hpd_irq_event(dp->drm_dev);
 }
 
-static void exynos_dp_commit(struct exynos_drm_display *display)
+static void exynos_dp_commit(struct drm_encoder *encoder)
 {
-       struct exynos_dp_device *dp = display_to_dp(display);
+       struct exynos_dp_device *dp = encoder_to_dp(encoder);
        int ret;
 
        /* Keep the panel disabled while we configure video */
@@ -938,6 +936,9 @@ static void exynos_dp_commit(struct exynos_drm_display *display)
                if (drm_panel_enable(dp->panel))
                        DRM_ERROR("failed to enable the panel\n");
        }
+
+       /* Enable video */
+       exynos_dp_start_video(dp);
 }
 
 static enum drm_connector_status exynos_dp_detect(
@@ -994,7 +995,7 @@ static struct drm_encoder *exynos_dp_best_encoder(
 {
        struct exynos_dp_device *dp = ctx_from_connector(connector);
 
-       return dp->encoder;
+       return &dp->encoder;
 }
 
 static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
@@ -1019,15 +1020,12 @@ static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
        return 0;
 }
 
-static int exynos_dp_create_connector(struct exynos_drm_display *display,
-                               struct drm_encoder *encoder)
+static int exynos_dp_create_connector(struct drm_encoder *encoder)
 {
-       struct exynos_dp_device *dp = display_to_dp(display);
+       struct exynos_dp_device *dp = encoder_to_dp(encoder);
        struct drm_connector *connector = &dp->connector;
        int ret;
 
-       dp->encoder = encoder;
-
        /* Pre-empt DP connector creation if there's a bridge */
        if (dp->bridge) {
                ret = exynos_drm_attach_lcd_bridge(dp, encoder);
@@ -1054,20 +1052,22 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display,
        return ret;
 }
 
-static void exynos_dp_phy_init(struct exynos_dp_device *dp)
+static bool exynos_dp_mode_fixup(struct drm_encoder *encoder,
+                                const struct drm_display_mode *mode,
+                                struct drm_display_mode *adjusted_mode)
 {
-       if (dp->phy)
-               phy_power_on(dp->phy);
+       return true;
 }
 
-static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
+static void exynos_dp_mode_set(struct drm_encoder *encoder,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode)
 {
-       if (dp->phy)
-               phy_power_off(dp->phy);
 }
 
-static void exynos_dp_poweron(struct exynos_dp_device *dp)
+static void exynos_dp_enable(struct drm_encoder *encoder)
 {
+       struct exynos_dp_device *dp = encoder_to_dp(encoder);
        struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
 
        if (dp->dpms_mode == DRM_MODE_DPMS_ON)
@@ -1084,14 +1084,17 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp)
                crtc->ops->clock_enable(dp_to_crtc(dp), true);
 
        clk_prepare_enable(dp->clock);
-       exynos_dp_phy_init(dp);
+       phy_power_on(dp->phy);
        exynos_dp_init_dp(dp);
        enable_irq(dp->irq);
-       exynos_dp_commit(&dp->display);
+       exynos_dp_commit(&dp->encoder);
+
+       dp->dpms_mode = DRM_MODE_DPMS_ON;
 }
 
-static void exynos_dp_poweroff(struct exynos_dp_device *dp)
+static void exynos_dp_disable(struct drm_encoder *encoder)
 {
+       struct exynos_dp_device *dp = encoder_to_dp(encoder);
        struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
 
        if (dp->dpms_mode != DRM_MODE_DPMS_ON)
@@ -1106,7 +1109,7 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp)
 
        disable_irq(dp->irq);
        flush_work(&dp->hotplug_work);
-       exynos_dp_phy_exit(dp);
+       phy_power_off(dp->phy);
        clk_disable_unprepare(dp->clock);
 
        if (crtc->ops->clock_enable)
@@ -1116,31 +1119,19 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp)
                if (drm_panel_unprepare(dp->panel))
                        DRM_ERROR("failed to turnoff the panel\n");
        }
-}
-
-static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
-{
-       struct exynos_dp_device *dp = display_to_dp(display);
 
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               exynos_dp_poweron(dp);
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               exynos_dp_poweroff(dp);
-               break;
-       default:
-               break;
-       }
-       dp->dpms_mode = mode;
+       dp->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
-static struct exynos_drm_display_ops exynos_dp_display_ops = {
-       .create_connector = exynos_dp_create_connector,
-       .dpms = exynos_dp_dpms,
-       .commit = exynos_dp_commit,
+static struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = {
+       .mode_fixup = exynos_dp_mode_fixup,
+       .mode_set = exynos_dp_mode_set,
+       .enable = exynos_dp_enable,
+       .disable = exynos_dp_disable,
+};
+
+static struct drm_encoder_funcs exynos_dp_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
 };
 
 static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
@@ -1219,9 +1210,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
        struct exynos_dp_device *dp = dev_get_drvdata(dev);
        struct platform_device *pdev = to_platform_device(dev);
        struct drm_device *drm_dev = data;
+       struct drm_encoder *encoder = &dp->encoder;
        struct resource *res;
        unsigned int irq_flags;
-       int ret = 0;
+       int pipe, ret = 0;
 
        dp->dev = &pdev->dev;
        dp->dpms_mode = DRM_MODE_DPMS_OFF;
@@ -1297,7 +1289,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
        INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
 
-       exynos_dp_phy_init(dp);
+       phy_power_on(dp->phy);
 
        exynos_dp_init_dp(dp);
 
@@ -1311,7 +1303,28 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
        dp->drm_dev = drm_dev;
 
-       return exynos_drm_create_enc_conn(drm_dev, &dp->display);
+       pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
+                                                 EXYNOS_DISPLAY_TYPE_LCD);
+       if (pipe < 0)
+               return pipe;
+
+       encoder->possible_crtcs = 1 << pipe;
+
+       DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+       drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+
+       drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs);
+
+       ret = exynos_dp_create_connector(encoder);
+       if (ret) {
+               DRM_ERROR("failed to create connector ret = %d\n", ret);
+               drm_encoder_cleanup(encoder);
+               return ret;
+       }
+
+       return 0;
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
@@ -1319,7 +1332,7 @@ static void exynos_dp_unbind(struct device *dev, struct device *master,
 {
        struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-       exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF);
+       exynos_dp_disable(&dp->encoder);
 }
 
 static const struct component_ops exynos_dp_ops = {
@@ -1338,8 +1351,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
        if (!dp)
                return -ENOMEM;
 
-       dp->display.type = EXYNOS_DISPLAY_TYPE_LCD;
-       dp->display.ops = &exynos_dp_display_ops;
        platform_set_drvdata(pdev, dp);
 
        panel_node = of_parse_phandle(dev->of_node, "panel", 0);
@@ -1377,7 +1388,7 @@ static int exynos_dp_suspend(struct device *dev)
 {
        struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-       exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF);
+       exynos_dp_disable(&dp->encoder);
        return 0;
 }
 
@@ -1385,7 +1396,7 @@ static int exynos_dp_resume(struct device *dev)
 {
        struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-       exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_ON);
+       exynos_dp_enable(&dp->encoder);
        return 0;
 }
 #endif
index a4e799679669420c3cb6d6920beee1c43684889d..e413b6f7b0e7d947f3d1d58a91fc99151ab97a34 100644 (file)
@@ -147,11 +147,10 @@ struct link_train {
 };
 
 struct exynos_dp_device {
-       struct exynos_drm_display display;
+       struct drm_encoder      encoder;
        struct device           *dev;
        struct drm_device       *drm_dev;
        struct drm_connector    connector;
-       struct drm_encoder      *encoder;
        struct drm_panel        *panel;
        struct drm_bridge       *bridge;
        struct clk              *clock;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
deleted file mode 100644 (file)
index 24994ba..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/* exynos_drm_buf.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Author: Inki Dae <inki.dae@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/exynos_drm.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_drm_gem.h"
-#include "exynos_drm_buf.h"
-#include "exynos_drm_iommu.h"
-
-static int lowlevel_buffer_allocate(struct drm_device *dev,
-               unsigned int flags, struct exynos_drm_gem_buf *buf)
-{
-       int ret = 0;
-       enum dma_attr attr;
-       unsigned int nr_pages;
-
-       if (buf->dma_addr) {
-               DRM_DEBUG_KMS("already allocated.\n");
-               return 0;
-       }
-
-       init_dma_attrs(&buf->dma_attrs);
-
-       /*
-        * if EXYNOS_BO_CONTIG, fully physically contiguous memory
-        * region will be allocated else physically contiguous
-        * as possible.
-        */
-       if (!(flags & EXYNOS_BO_NONCONTIG))
-               dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs);
-
-       /*
-        * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
-        * else cachable mapping.
-        */
-       if (flags & EXYNOS_BO_WC || !(flags & EXYNOS_BO_CACHABLE))
-               attr = DMA_ATTR_WRITE_COMBINE;
-       else
-               attr = DMA_ATTR_NON_CONSISTENT;
-
-       dma_set_attr(attr, &buf->dma_attrs);
-       dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs);
-
-       nr_pages = buf->size >> PAGE_SHIFT;
-
-       if (!is_drm_iommu_supported(dev)) {
-               dma_addr_t start_addr;
-               unsigned int i = 0;
-
-               buf->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
-               if (!buf->pages) {
-                       DRM_ERROR("failed to allocate pages.\n");
-                       return -ENOMEM;
-               }
-
-               buf->cookie = dma_alloc_attrs(dev->dev,
-                                       buf->size,
-                                       &buf->dma_addr, GFP_KERNEL,
-                                       &buf->dma_attrs);
-               if (!buf->cookie) {
-                       DRM_ERROR("failed to allocate buffer.\n");
-                       ret = -ENOMEM;
-                       goto err_free;
-               }
-
-               start_addr = buf->dma_addr;
-               while (i < nr_pages) {
-                       buf->pages[i] = phys_to_page(start_addr);
-                       start_addr += PAGE_SIZE;
-                       i++;
-               }
-       } else {
-
-               buf->pages = dma_alloc_attrs(dev->dev, buf->size,
-                                       &buf->dma_addr, GFP_KERNEL,
-                                       &buf->dma_attrs);
-               if (!buf->pages) {
-                       DRM_ERROR("failed to allocate buffer.\n");
-                       return -ENOMEM;
-               }
-       }
-
-       buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
-       if (IS_ERR(buf->sgt)) {
-               DRM_ERROR("failed to get sg table.\n");
-               ret = PTR_ERR(buf->sgt);
-               goto err_free_attrs;
-       }
-
-       DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
-                       (unsigned long)buf->dma_addr,
-                       buf->size);
-
-       return ret;
-
-err_free_attrs:
-       dma_free_attrs(dev->dev, buf->size, buf->pages,
-                       (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
-       buf->dma_addr = (dma_addr_t)NULL;
-err_free:
-       if (!is_drm_iommu_supported(dev))
-               drm_free_large(buf->pages);
-
-       return ret;
-}
-
-static void lowlevel_buffer_deallocate(struct drm_device *dev,
-               unsigned int flags, struct exynos_drm_gem_buf *buf)
-{
-       if (!buf->dma_addr) {
-               DRM_DEBUG_KMS("dma_addr is invalid.\n");
-               return;
-       }
-
-       DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
-                       (unsigned long)buf->dma_addr,
-                       buf->size);
-
-       sg_free_table(buf->sgt);
-
-       kfree(buf->sgt);
-       buf->sgt = NULL;
-
-       if (!is_drm_iommu_supported(dev)) {
-               dma_free_attrs(dev->dev, buf->size, buf->cookie,
-                               (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
-               drm_free_large(buf->pages);
-       } else
-               dma_free_attrs(dev->dev, buf->size, buf->pages,
-                               (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
-
-       buf->dma_addr = (dma_addr_t)NULL;
-}
-
-struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
-                                               unsigned int size)
-{
-       struct exynos_drm_gem_buf *buffer;
-
-       DRM_DEBUG_KMS("desired size = 0x%x\n", size);
-
-       buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
-       if (!buffer)
-               return NULL;
-
-       buffer->size = size;
-       return buffer;
-}
-
-void exynos_drm_fini_buf(struct drm_device *dev,
-                               struct exynos_drm_gem_buf *buffer)
-{
-       kfree(buffer);
-       buffer = NULL;
-}
-
-int exynos_drm_alloc_buf(struct drm_device *dev,
-               struct exynos_drm_gem_buf *buf, unsigned int flags)
-{
-
-       /*
-        * allocate memory region and set the memory information
-        * to vaddr and dma_addr of a buffer object.
-        */
-       if (lowlevel_buffer_allocate(dev, flags, buf) < 0)
-               return -ENOMEM;
-
-       return 0;
-}
-
-void exynos_drm_free_buf(struct drm_device *dev,
-               unsigned int flags, struct exynos_drm_gem_buf *buffer)
-{
-
-       lowlevel_buffer_deallocate(dev, flags, buffer);
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h
deleted file mode 100644 (file)
index a6412f1..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* exynos_drm_buf.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Author: Inki Dae <inki.dae@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_BUF_H_
-#define _EXYNOS_DRM_BUF_H_
-
-/* create and initialize buffer object. */
-struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
-                                               unsigned int size);
-
-/* destroy buffer object. */
-void exynos_drm_fini_buf(struct drm_device *dev,
-                               struct exynos_drm_gem_buf *buffer);
-
-/* allocate physical memory region and setup sgt. */
-int exynos_drm_alloc_buf(struct drm_device *dev,
-                               struct exynos_drm_gem_buf *buf,
-                               unsigned int flags);
-
-/* release physical memory region, and sgt. */
-void exynos_drm_free_buf(struct drm_device *dev,
-                               unsigned int flags,
-                               struct exynos_drm_gem_buf *buffer);
-
-#endif
index 4c9f972eaa0771c0b2d9c5ff0f5480da3dc1e93d..c68a6a2a9b5794558015abdeefb0e58c4958049d 100644 (file)
 #include <drm/drmP.h>
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
-#include "exynos_drm_encoder.h"
 #include "exynos_drm_fbdev.h"
 
 static LIST_HEAD(exynos_drm_subdrv_list);
 
-int exynos_drm_create_enc_conn(struct drm_device *dev,
-                                       struct exynos_drm_display *display)
-{
-       struct drm_encoder *encoder;
-       int ret;
-       unsigned long possible_crtcs = 0;
-
-       ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type);
-       if (ret < 0)
-               return ret;
-
-       possible_crtcs |= 1 << ret;
-
-       /* create and initialize a encoder for this sub driver. */
-       encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
-       if (!encoder) {
-               DRM_ERROR("failed to create encoder\n");
-               return -EFAULT;
-       }
-
-       display->encoder = encoder;
-
-       ret = display->ops->create_connector(display, encoder);
-       if (ret) {
-               DRM_ERROR("failed to create connector ret = %d\n", ret);
-               goto err_destroy_encoder;
-       }
-
-       return 0;
-
-err_destroy_encoder:
-       encoder->funcs->destroy(encoder);
-       return ret;
-}
-
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
 {
        if (!subdrv)
index 644b4b76e07176e3df75b0415227eac162fb3d26..c47899738eb48fe44ff60681fff06b9122afaed8 100644 (file)
@@ -19,7 +19,6 @@
 
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_drv.h"
-#include "exynos_drm_encoder.h"
 #include "exynos_drm_plane.h"
 
 static void exynos_drm_crtc_enable(struct drm_crtc *crtc)
@@ -80,7 +79,8 @@ exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
                exynos_crtc->ops->commit(exynos_crtc);
 }
 
-static void exynos_crtc_atomic_begin(struct drm_crtc *crtc)
+static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
+                                    struct drm_crtc_state *old_crtc_state)
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
@@ -90,7 +90,8 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc)
        }
 }
 
-static void exynos_crtc_atomic_flush(struct drm_crtc *crtc)
+static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
+                                    struct drm_crtc_state *old_crtc_state)
 {
 }
 
@@ -175,7 +176,7 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
                return -EPERM;
 
        if (exynos_crtc->ops->enable_vblank)
-               exynos_crtc->ops->enable_vblank(exynos_crtc);
+               return exynos_crtc->ops->enable_vblank(exynos_crtc);
 
        return 0;
 }
@@ -193,24 +194,22 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
                exynos_crtc->ops->disable_vblank(exynos_crtc);
 }
 
-void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
+void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc)
 {
-       struct exynos_drm_private *dev_priv = dev->dev_private;
-       struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
-       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
+       struct drm_crtc *crtc = &exynos_crtc->base;
        unsigned long flags;
 
-       spin_lock_irqsave(&dev->event_lock, flags);
+       spin_lock_irqsave(&crtc->dev->event_lock, flags);
        if (exynos_crtc->event) {
 
-               drm_send_vblank_event(dev, -1, exynos_crtc->event);
-               drm_vblank_put(dev, pipe);
+               drm_crtc_send_vblank_event(crtc, exynos_crtc->event);
+               drm_crtc_vblank_put(crtc);
                wake_up(&exynos_crtc->pending_flip_queue);
 
        }
 
        exynos_crtc->event = NULL;
-       spin_unlock_irqrestore(&dev->event_lock, flags);
+       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 }
 
 void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
@@ -237,7 +236,7 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
 }
 
 int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
-                                       unsigned int out_type)
+                                      enum exynos_drm_output_type out_type)
 {
        struct drm_crtc *crtc;
 
index 0f3aa70818e31059bfc6369c258dcd326fa07d53..9e7027d6c2f6de7a2b58bd5852165063c6625547 100644 (file)
@@ -25,12 +25,12 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
                                        void *context);
 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
 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_finish_pageflip(struct exynos_drm_crtc *exynos_crtc);
 void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
 
 /* 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);
+                                      enum exynos_drm_output_type out_type);
 
 /*
  * This function calls the crtc device(manager)'s te_handler() callback
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
deleted file mode 100644 (file)
index cd485c0..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-/* exynos_drm_dmabuf.c
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * Author: Inki Dae <inki.dae@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/exynos_drm.h>
-#include "exynos_drm_dmabuf.h"
-#include "exynos_drm_drv.h"
-#include "exynos_drm_gem.h"
-
-#include <linux/dma-buf.h>
-
-struct exynos_drm_dmabuf_attachment {
-       struct sg_table sgt;
-       enum dma_data_direction dir;
-       bool is_mapped;
-};
-
-static struct exynos_drm_gem_obj *dma_buf_to_obj(struct dma_buf *buf)
-{
-       return to_exynos_gem_obj(buf->priv);
-}
-
-static int exynos_gem_attach_dma_buf(struct dma_buf *dmabuf,
-                                       struct device *dev,
-                                       struct dma_buf_attachment *attach)
-{
-       struct exynos_drm_dmabuf_attachment *exynos_attach;
-
-       exynos_attach = kzalloc(sizeof(*exynos_attach), GFP_KERNEL);
-       if (!exynos_attach)
-               return -ENOMEM;
-
-       exynos_attach->dir = DMA_NONE;
-       attach->priv = exynos_attach;
-
-       return 0;
-}
-
-static void exynos_gem_detach_dma_buf(struct dma_buf *dmabuf,
-                                       struct dma_buf_attachment *attach)
-{
-       struct exynos_drm_dmabuf_attachment *exynos_attach = attach->priv;
-       struct sg_table *sgt;
-
-       if (!exynos_attach)
-               return;
-
-       sgt = &exynos_attach->sgt;
-
-       if (exynos_attach->dir != DMA_NONE)
-               dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
-                               exynos_attach->dir);
-
-       sg_free_table(sgt);
-       kfree(exynos_attach);
-       attach->priv = NULL;
-}
-
-static struct sg_table *
-               exynos_gem_map_dma_buf(struct dma_buf_attachment *attach,
-                                       enum dma_data_direction dir)
-{
-       struct exynos_drm_dmabuf_attachment *exynos_attach = attach->priv;
-       struct exynos_drm_gem_obj *gem_obj = dma_buf_to_obj(attach->dmabuf);
-       struct drm_device *dev = gem_obj->base.dev;
-       struct exynos_drm_gem_buf *buf;
-       struct scatterlist *rd, *wr;
-       struct sg_table *sgt = NULL;
-       unsigned int i;
-       int nents, ret;
-
-       /* just return current sgt if already requested. */
-       if (exynos_attach->dir == dir && exynos_attach->is_mapped)
-               return &exynos_attach->sgt;
-
-       buf = gem_obj->buffer;
-       if (!buf) {
-               DRM_ERROR("buffer is null.\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       sgt = &exynos_attach->sgt;
-
-       ret = sg_alloc_table(sgt, buf->sgt->orig_nents, GFP_KERNEL);
-       if (ret) {
-               DRM_ERROR("failed to alloc sgt.\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       mutex_lock(&dev->struct_mutex);
-
-       rd = buf->sgt->sgl;
-       wr = sgt->sgl;
-       for (i = 0; i < sgt->orig_nents; ++i) {
-               sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
-               rd = sg_next(rd);
-               wr = sg_next(wr);
-       }
-
-       if (dir != DMA_NONE) {
-               nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
-               if (!nents) {
-                       DRM_ERROR("failed to map sgl with iommu.\n");
-                       sg_free_table(sgt);
-                       sgt = ERR_PTR(-EIO);
-                       goto err_unlock;
-               }
-       }
-
-       exynos_attach->is_mapped = true;
-       exynos_attach->dir = dir;
-       attach->priv = exynos_attach;
-
-       DRM_DEBUG_PRIME("buffer size = 0x%lx\n", buf->size);
-
-err_unlock:
-       mutex_unlock(&dev->struct_mutex);
-       return sgt;
-}
-
-static void exynos_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
-                                               struct sg_table *sgt,
-                                               enum dma_data_direction dir)
-{
-       /* Nothing to do. */
-}
-
-static void *exynos_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
-                                               unsigned long page_num)
-{
-       /* TODO */
-
-       return NULL;
-}
-
-static void exynos_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
-                                               unsigned long page_num,
-                                               void *addr)
-{
-       /* TODO */
-}
-
-static void *exynos_gem_dmabuf_kmap(struct dma_buf *dma_buf,
-                                       unsigned long page_num)
-{
-       /* TODO */
-
-       return NULL;
-}
-
-static void exynos_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
-                                       unsigned long page_num, void *addr)
-{
-       /* TODO */
-}
-
-static int exynos_gem_dmabuf_mmap(struct dma_buf *dma_buf,
-       struct vm_area_struct *vma)
-{
-       return -ENOTTY;
-}
-
-static struct dma_buf_ops exynos_dmabuf_ops = {
-       .attach                 = exynos_gem_attach_dma_buf,
-       .detach                 = exynos_gem_detach_dma_buf,
-       .map_dma_buf            = exynos_gem_map_dma_buf,
-       .unmap_dma_buf          = exynos_gem_unmap_dma_buf,
-       .kmap                   = exynos_gem_dmabuf_kmap,
-       .kmap_atomic            = exynos_gem_dmabuf_kmap_atomic,
-       .kunmap                 = exynos_gem_dmabuf_kunmap,
-       .kunmap_atomic          = exynos_gem_dmabuf_kunmap_atomic,
-       .mmap                   = exynos_gem_dmabuf_mmap,
-       .release                = drm_gem_dmabuf_release,
-};
-
-struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
-                               struct drm_gem_object *obj, int flags)
-{
-       struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
-       DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-
-       exp_info.ops = &exynos_dmabuf_ops;
-       exp_info.size = exynos_gem_obj->base.size;
-       exp_info.flags = flags;
-       exp_info.priv = obj;
-
-       return dma_buf_export(&exp_info);
-}
-
-struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
-                               struct dma_buf *dma_buf)
-{
-       struct dma_buf_attachment *attach;
-       struct sg_table *sgt;
-       struct scatterlist *sgl;
-       struct exynos_drm_gem_obj *exynos_gem_obj;
-       struct exynos_drm_gem_buf *buffer;
-       int ret;
-
-       /* is this one of own objects? */
-       if (dma_buf->ops == &exynos_dmabuf_ops) {
-               struct drm_gem_object *obj;
-
-               obj = dma_buf->priv;
-
-               /* is it from our device? */
-               if (obj->dev == drm_dev) {
-                       /*
-                        * Importing dmabuf exported from out own gem increases
-                        * refcount on gem itself instead of f_count of dmabuf.
-                        */
-                       drm_gem_object_reference(obj);
-                       return obj;
-               }
-       }
-
-       attach = dma_buf_attach(dma_buf, drm_dev->dev);
-       if (IS_ERR(attach))
-               return ERR_PTR(-EINVAL);
-
-       get_dma_buf(dma_buf);
-
-       sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
-       if (IS_ERR(sgt)) {
-               ret = PTR_ERR(sgt);
-               goto err_buf_detach;
-       }
-
-       buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
-       if (!buffer) {
-               ret = -ENOMEM;
-               goto err_unmap_attach;
-       }
-
-       exynos_gem_obj = exynos_drm_gem_init(drm_dev, dma_buf->size);
-       if (!exynos_gem_obj) {
-               ret = -ENOMEM;
-               goto err_free_buffer;
-       }
-
-       sgl = sgt->sgl;
-
-       buffer->size = dma_buf->size;
-       buffer->dma_addr = sg_dma_address(sgl);
-
-       if (sgt->nents == 1) {
-               /* always physically continuous memory if sgt->nents is 1. */
-               exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
-       } else {
-               /*
-                * this case could be CONTIG or NONCONTIG type but for now
-                * sets NONCONTIG.
-                * TODO. we have to find a way that exporter can notify
-                * the type of its own buffer to importer.
-                */
-               exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
-       }
-
-       exynos_gem_obj->buffer = buffer;
-       buffer->sgt = sgt;
-       exynos_gem_obj->base.import_attach = attach;
-
-       DRM_DEBUG_PRIME("dma_addr = %pad, size = 0x%lx\n", &buffer->dma_addr,
-                                                               buffer->size);
-
-       return &exynos_gem_obj->base;
-
-err_free_buffer:
-       kfree(buffer);
-       buffer = NULL;
-err_unmap_attach:
-       dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
-err_buf_detach:
-       dma_buf_detach(dma_buf, attach);
-       dma_buf_put(dma_buf);
-
-       return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
deleted file mode 100644 (file)
index 886de9f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* exynos_drm_dmabuf.h
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * Author: Inki Dae <inki.dae@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_DMABUF_H_
-#define _EXYNOS_DRM_DMABUF_H_
-
-struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
-                               struct drm_gem_object *obj, int flags);
-
-struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
-                                               struct dma_buf *dma_buf);
-#endif
index 7cb6595c1894146fb802f0b89d25001f5a3d393b..c748b8790de3ecad22bcd2c5f6276a4223ccfd10 100644 (file)
 #include <video/of_videomode.h>
 #include <video/videomode.h>
 
-#include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
 
 struct exynos_dpi {
-       struct exynos_drm_display display;
+       struct drm_encoder encoder;
        struct device *dev;
        struct device_node *panel_node;
 
        struct drm_panel *panel;
        struct drm_connector connector;
-       struct drm_encoder *encoder;
 
        struct videomode *vm;
-       int dpms_mode;
 };
 
 #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector)
 
-static inline struct exynos_dpi *display_to_dpi(struct exynos_drm_display *d)
+static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e)
 {
-       return container_of(d, struct exynos_dpi, display);
+       return container_of(e, struct exynos_dpi, encoder);
 }
 
 static enum drm_connector_status
@@ -99,7 +97,7 @@ exynos_dpi_best_encoder(struct drm_connector *connector)
 {
        struct exynos_dpi *ctx = connector_to_dpi(connector);
 
-       return ctx->encoder;
+       return &ctx->encoder;
 }
 
 static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
@@ -107,15 +105,12 @@ static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
        .best_encoder = exynos_dpi_best_encoder,
 };
 
-static int exynos_dpi_create_connector(struct exynos_drm_display *display,
-                                      struct drm_encoder *encoder)
+static int exynos_dpi_create_connector(struct drm_encoder *encoder)
 {
-       struct exynos_dpi *ctx = display_to_dpi(display);
+       struct exynos_dpi *ctx = encoder_to_dpi(encoder);
        struct drm_connector *connector = &ctx->connector;
        int ret;
 
-       ctx->encoder = encoder;
-
        connector->polled = DRM_CONNECTOR_POLL_HPD;
 
        ret = drm_connector_init(encoder->dev, connector,
@@ -133,46 +128,48 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display,
        return 0;
 }
 
-static void exynos_dpi_poweron(struct exynos_dpi *ctx)
+static bool exynos_dpi_mode_fixup(struct drm_encoder *encoder,
+                                 const struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void exynos_dpi_mode_set(struct drm_encoder *encoder,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
 {
+}
+
+static void exynos_dpi_enable(struct drm_encoder *encoder)
+{
+       struct exynos_dpi *ctx = encoder_to_dpi(encoder);
+
        if (ctx->panel) {
                drm_panel_prepare(ctx->panel);
                drm_panel_enable(ctx->panel);
        }
 }
 
-static void exynos_dpi_poweroff(struct exynos_dpi *ctx)
+static void exynos_dpi_disable(struct drm_encoder *encoder)
 {
+       struct exynos_dpi *ctx = encoder_to_dpi(encoder);
+
        if (ctx->panel) {
                drm_panel_disable(ctx->panel);
                drm_panel_unprepare(ctx->panel);
        }
 }
 
-static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode)
-{
-       struct exynos_dpi *ctx = display_to_dpi(display);
-
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               if (ctx->dpms_mode != DRM_MODE_DPMS_ON)
-                               exynos_dpi_poweron(ctx);
-                       break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               if (ctx->dpms_mode == DRM_MODE_DPMS_ON)
-                       exynos_dpi_poweroff(ctx);
-               break;
-       default:
-               break;
-       }
-       ctx->dpms_mode = mode;
-}
+static struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {
+       .mode_fixup = exynos_dpi_mode_fixup,
+       .mode_set = exynos_dpi_mode_set,
+       .enable = exynos_dpi_enable,
+       .disable = exynos_dpi_disable,
+};
 
-static struct exynos_drm_display_ops exynos_dpi_display_ops = {
-       .create_connector = exynos_dpi_create_connector,
-       .dpms = exynos_dpi_dpms
+static struct drm_encoder_funcs exynos_dpi_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
 };
 
 /* of_* functions will be removed after merge of of_graph patches */
@@ -299,7 +296,34 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
        return 0;
 }
 
-struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
+int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder)
+{
+       int ret;
+
+       ret = exynos_drm_crtc_get_pipe_from_type(dev, EXYNOS_DISPLAY_TYPE_LCD);
+       if (ret < 0)
+               return ret;
+
+       encoder->possible_crtcs = 1 << ret;
+
+       DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+       drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+
+       drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs);
+
+       ret = exynos_dpi_create_connector(encoder);
+       if (ret) {
+               DRM_ERROR("failed to create connector ret = %d\n", ret);
+               drm_encoder_cleanup(encoder);
+               return ret;
+       }
+
+       return 0;
+}
+
+struct drm_encoder *exynos_dpi_probe(struct device *dev)
 {
        struct exynos_dpi *ctx;
        int ret;
@@ -308,10 +332,7 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
        if (!ctx)
                return ERR_PTR(-ENOMEM);
 
-       ctx->display.type = EXYNOS_DISPLAY_TYPE_LCD;
-       ctx->display.ops = &exynos_dpi_display_ops;
        ctx->dev = dev;
-       ctx->dpms_mode = DRM_MODE_DPMS_OFF;
 
        ret = exynos_dpi_parse_dt(ctx);
        if (ret < 0) {
@@ -325,14 +346,14 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
                        return ERR_PTR(-EPROBE_DEFER);
        }
 
-       return &ctx->display;
+       return &ctx->encoder;
 }
 
-int exynos_dpi_remove(struct exynos_drm_display *display)
+int exynos_dpi_remove(struct drm_encoder *encoder)
 {
-       struct exynos_dpi *ctx = display_to_dpi(display);
+       struct exynos_dpi *ctx = encoder_to_dpi(encoder);
 
-       exynos_dpi_dpms(&ctx->display, DRM_MODE_DPMS_OFF);
+       exynos_dpi_disable(&ctx->encoder);
 
        if (ctx->panel)
                drm_panel_detach(ctx->panel);
index 63a68c60a3536d6862eec045677e210ba8b87c73..fa5194caf2590dbc34df0313dc858c05a454642e 100644 (file)
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
-#include "exynos_drm_encoder.h"
 #include "exynos_drm_fbdev.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_plane.h"
 #include "exynos_drm_vidi.h"
-#include "exynos_drm_dmabuf.h"
 #include "exynos_drm_g2d.h"
 #include "exynos_drm_ipp.h"
 #include "exynos_drm_iommu.h"
@@ -41,7 +39,9 @@
 static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 {
        struct exynos_drm_private *private;
-       int ret;
+       struct drm_encoder *encoder;
+       unsigned int clone_mask;
+       int cnt, ret;
 
        private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
        if (!private)
@@ -67,7 +67,13 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
        exynos_drm_mode_config_init(dev);
 
        /* setup possible_clones. */
-       exynos_drm_encoder_setup(dev);
+       cnt = 0;
+       clone_mask = 0;
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               clone_mask |= (1 << (cnt++));
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               encoder->possible_clones = clone_mask;
 
        platform_set_drvdata(dev->platformdev, dev);
 
@@ -297,8 +303,12 @@ static struct drm_driver exynos_drm_driver = {
        .dumb_destroy           = drm_gem_dumb_destroy,
        .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
        .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
-       .gem_prime_export       = exynos_dmabuf_prime_export,
-       .gem_prime_import       = exynos_dmabuf_prime_import,
+       .gem_prime_export       = drm_gem_prime_export,
+       .gem_prime_import       = drm_gem_prime_import,
+       .gem_prime_get_sg_table = exynos_drm_gem_prime_get_sg_table,
+       .gem_prime_import_sg_table      = exynos_drm_gem_prime_import_sg_table,
+       .gem_prime_vmap         = exynos_drm_gem_prime_vmap,
+       .gem_prime_vunmap       = exynos_drm_gem_prime_vunmap,
        .ioctls                 = exynos_ioctls,
        .num_ioctls             = ARRAY_SIZE(exynos_ioctls),
        .fops                   = &exynos_drm_driver_fops,
@@ -345,9 +355,6 @@ static struct platform_driver exynos_drm_platform_driver;
  * because connector requires pipe number of its crtc during initialization.
  */
 static struct platform_driver *const exynos_drm_kms_drivers[] = {
-#ifdef CONFIG_DRM_EXYNOS_VIDI
-       &vidi_driver,
-#endif
 #ifdef CONFIG_DRM_EXYNOS_FIMD
        &fimd_driver,
 #endif
@@ -370,6 +377,9 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = {
        &mixer_driver,
        &hdmi_driver,
 #endif
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+       &vidi_driver,
+#endif
 };
 
 static struct platform_driver *const exynos_drm_non_kms_drivers[] = {
index dd00f160c1e58c9563341a5736d5d19d07932da7..6b8a30f23473d694e68e302aeb4f3593147f1c35 100644 (file)
@@ -44,23 +44,14 @@ enum exynos_drm_output_type {
  *     - the unit is screen coordinates.
  * @src_y: offset y on a framebuffer to be displayed.
  *     - the unit is screen coordinates.
- * @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.
+ * @src_w: width of a partial image to be displayed from framebuffer.
+ * @src_h: height of a partial image to be displayed from 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.
+ * @crtc_w: window width to be displayed (hardware screen).
+ * @crtc_h: window height to be displayed (hardware screen).
  * @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_*)
- * @bpp: pixel size.(in bit)
- * @pixel_format: fourcc pixel format of this overlay
  * @dma_addr: array of bus(accessed by dma) address to the memory region
  *           allocated for a overlay.
  * @zpos: order of overlay layer(z position).
@@ -73,75 +64,18 @@ struct exynos_drm_plane {
        struct drm_plane base;
        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 src_w;
+       unsigned int src_h;
        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 crtc_w;
+       unsigned int crtc_h;
        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];
        unsigned int zpos;
 };
 
-/*
- * Exynos DRM Display Structure.
- *     - this structure is common to analog tv, digital tv and lcd panel.
- *
- * @create_connector: initialize and register a new connector
- * @remove: cleans up the display for removal
- * @mode_fixup: fix mode data comparing to hw specific display mode.
- * @mode_set: convert drm_display_mode to hw specific display mode and
- *           would be called by encoder->mode_set().
- * @check_mode: check if mode is valid or not.
- * @dpms: display device on or off.
- * @commit: apply changes to hw
- */
-struct exynos_drm_display;
-struct exynos_drm_display_ops {
-       int (*create_connector)(struct exynos_drm_display *display,
-                               struct drm_encoder *encoder);
-       void (*remove)(struct exynos_drm_display *display);
-       void (*mode_fixup)(struct exynos_drm_display *display,
-                               struct drm_connector *connector,
-                               const struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode);
-       void (*mode_set)(struct exynos_drm_display *display,
-                               struct drm_display_mode *mode);
-       int (*check_mode)(struct exynos_drm_display *display,
-                               struct drm_display_mode *mode);
-       void (*dpms)(struct exynos_drm_display *display, int mode);
-       void (*commit)(struct exynos_drm_display *display);
-};
-
-/*
- * Exynos drm display structure, maps 1:1 with an encoder/connector
- *
- * @list: the list entry for this manager
- * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
- * @encoder: encoder object this display maps to
- * @connector: connector object this display maps to
- * @ops: pointer to callbacks for exynos drm specific functionality
- * @ctx: A pointer to the display's implementation specific context
- */
-struct exynos_drm_display {
-       struct list_head list;
-       enum exynos_drm_output_type type;
-       struct drm_encoder *encoder;
-       struct drm_connector *connector;
-       struct exynos_drm_display_ops *ops;
-};
-
 /*
  * Exynos drm crtc ops
  *
@@ -153,8 +87,8 @@ 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_commit: apply hardware specific overlay data to registers.
- * @win_disable: disable hardware specific overlay.
+ * @update_plane: apply hardware specific overlay data to registers.
+ * @disable_plane: disable hardware specific overlay.
  * @te_handler: trigger to transfer video image at the tearing effect
  *     synchronization signal if there is a page flip request.
  * @clock_enable: optional function enabling/disabling display domain clock,
@@ -173,11 +107,12 @@ 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_commit)(struct exynos_drm_crtc *crtc, unsigned int zpos);
-       void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos);
+       void (*update_plane)(struct exynos_drm_crtc *crtc,
+                            struct exynos_drm_plane *plane);
+       void (*disable_plane)(struct exynos_drm_crtc *crtc,
+                             struct exynos_drm_plane *plane);
        void (*te_handler)(struct exynos_drm_crtc *crtc);
        void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable);
-       void (*clear_channels)(struct exynos_drm_crtc *crtc);
 };
 
 /*
@@ -285,20 +220,23 @@ int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
 void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
 
 #ifdef CONFIG_DRM_EXYNOS_DPI
-struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
-int exynos_dpi_remove(struct exynos_drm_display *display);
+struct drm_encoder *exynos_dpi_probe(struct device *dev);
+int exynos_dpi_remove(struct drm_encoder *encoder);
+int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder);
 #else
-static inline struct exynos_drm_display *
+static inline struct drm_encoder *
 exynos_dpi_probe(struct device *dev) { return NULL; }
-static inline int exynos_dpi_remove(struct exynos_drm_display *display)
+static inline int exynos_dpi_remove(struct drm_encoder *encoder)
+{
+       return 0;
+}
+static inline int exynos_dpi_bind(struct drm_device *dev,
+                                 struct drm_encoder *encoder)
 {
        return 0;
 }
 #endif
 
-/* This function creates a encoder and a connector, and initializes them. */
-int exynos_drm_create_enc_conn(struct drm_device *dev,
-                               struct exynos_drm_display *display);
 
 extern struct platform_driver fimd_driver;
 extern struct platform_driver exynos5433_decon_driver;
index 0e58b36cb8c28f0b6fd725e93fd4730c744af939..12b03b3647034134411ffd1723f5c3c8141c979c 100644 (file)
@@ -259,7 +259,7 @@ struct exynos_dsi_driver_data {
 };
 
 struct exynos_dsi {
-       struct exynos_drm_display display;
+       struct drm_encoder encoder;
        struct mipi_dsi_host dsi_host;
        struct drm_connector connector;
        struct device_node *panel_node;
@@ -295,9 +295,9 @@ struct exynos_dsi {
 #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
 #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
 
-static inline struct exynos_dsi *display_to_dsi(struct exynos_drm_display *d)
+static inline struct exynos_dsi *encoder_to_dsi(struct drm_encoder *e)
 {
-       return container_of(d, struct exynos_dsi, display);
+       return container_of(e, struct exynos_dsi, encoder);
 }
 
 enum reg_idx {
@@ -1272,7 +1272,7 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id)
 static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id)
 {
        struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id;
-       struct drm_encoder *encoder = dsi->display.encoder;
+       struct drm_encoder *encoder = &dsi->encoder;
 
        if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE)
                exynos_drm_crtc_te_handler(encoder->crtc);
@@ -1518,16 +1518,17 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi)
                dev_err(dsi->dev, "cannot disable regulators %d\n", ret);
 }
 
-static int exynos_dsi_enable(struct exynos_dsi *dsi)
+static void exynos_dsi_enable(struct drm_encoder *encoder)
 {
+       struct exynos_dsi *dsi = encoder_to_dsi(encoder);
        int ret;
 
        if (dsi->state & DSIM_STATE_ENABLED)
-               return 0;
+               return;
 
        ret = exynos_dsi_poweron(dsi);
        if (ret < 0)
-               return ret;
+               return;
 
        dsi->state |= DSIM_STATE_ENABLED;
 
@@ -1535,7 +1536,7 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
        if (ret < 0) {
                dsi->state &= ~DSIM_STATE_ENABLED;
                exynos_dsi_poweroff(dsi);
-               return ret;
+               return;
        }
 
        exynos_dsi_set_display_mode(dsi);
@@ -1547,16 +1548,16 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
                exynos_dsi_set_display_enable(dsi, false);
                drm_panel_unprepare(dsi->panel);
                exynos_dsi_poweroff(dsi);
-               return ret;
+               return;
        }
 
        dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
-
-       return 0;
 }
 
-static void exynos_dsi_disable(struct exynos_dsi *dsi)
+static void exynos_dsi_disable(struct drm_encoder *encoder)
 {
+       struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+
        if (!(dsi->state & DSIM_STATE_ENABLED))
                return;
 
@@ -1571,26 +1572,6 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi)
        exynos_dsi_poweroff(dsi);
 }
 
-static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode)
-{
-       struct exynos_dsi *dsi = display_to_dsi(display);
-
-       if (dsi->panel) {
-               switch (mode) {
-               case DRM_MODE_DPMS_ON:
-                       exynos_dsi_enable(dsi);
-                       break;
-               case DRM_MODE_DPMS_STANDBY:
-               case DRM_MODE_DPMS_SUSPEND:
-               case DRM_MODE_DPMS_OFF:
-                       exynos_dsi_disable(dsi);
-                       break;
-               default:
-                       break;
-               }
-       }
-}
-
 static enum drm_connector_status
 exynos_dsi_detect(struct drm_connector *connector, bool force)
 {
@@ -1601,10 +1582,10 @@ exynos_dsi_detect(struct drm_connector *connector, bool force)
                if (dsi->panel)
                        drm_panel_attach(dsi->panel, &dsi->connector);
        } else if (!dsi->panel_node) {
-               struct exynos_drm_display *display;
+               struct drm_encoder *encoder;
 
-               display = platform_get_drvdata(to_platform_device(dsi->dev));
-               exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF);
+               encoder = platform_get_drvdata(to_platform_device(dsi->dev));
+               exynos_dsi_disable(encoder);
                drm_panel_detach(dsi->panel);
                dsi->panel = NULL;
        }
@@ -1647,7 +1628,7 @@ exynos_dsi_best_encoder(struct drm_connector *connector)
 {
        struct exynos_dsi *dsi = connector_to_dsi(connector);
 
-       return dsi->display.encoder;
+       return &dsi->encoder;
 }
 
 static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
@@ -1655,10 +1636,9 @@ static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
        .best_encoder = exynos_dsi_best_encoder,
 };
 
-static int exynos_dsi_create_connector(struct exynos_drm_display *display,
-                                      struct drm_encoder *encoder)
+static int exynos_dsi_create_connector(struct drm_encoder *encoder)
 {
-       struct exynos_dsi *dsi = display_to_dsi(display);
+       struct exynos_dsi *dsi = encoder_to_dsi(encoder);
        struct drm_connector *connector = &dsi->connector;
        int ret;
 
@@ -1679,26 +1659,40 @@ static int exynos_dsi_create_connector(struct exynos_drm_display *display,
        return 0;
 }
 
-static void exynos_dsi_mode_set(struct exynos_drm_display *display,
-                        struct drm_display_mode *mode)
+static bool exynos_dsi_mode_fixup(struct drm_encoder *encoder,
+                                 const struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
 {
-       struct exynos_dsi *dsi = display_to_dsi(display);
-       struct videomode *vm = &dsi->vm;
+       return true;
+}
 
-       vm->hactive = mode->hdisplay;
-       vm->vactive = mode->vdisplay;
-       vm->vfront_porch = mode->vsync_start - mode->vdisplay;
-       vm->vback_porch = mode->vtotal - mode->vsync_end;
-       vm->vsync_len = mode->vsync_end - mode->vsync_start;
-       vm->hfront_porch = mode->hsync_start - mode->hdisplay;
-       vm->hback_porch = mode->htotal - mode->hsync_end;
-       vm->hsync_len = mode->hsync_end - mode->hsync_start;
+static void exynos_dsi_mode_set(struct drm_encoder *encoder,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
+{
+       struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+       struct videomode *vm = &dsi->vm;
+       struct drm_display_mode *m = adjusted_mode;
+
+       vm->hactive = m->hdisplay;
+       vm->vactive = m->vdisplay;
+       vm->vfront_porch = m->vsync_start - m->vdisplay;
+       vm->vback_porch = m->vtotal - m->vsync_end;
+       vm->vsync_len = m->vsync_end - m->vsync_start;
+       vm->hfront_porch = m->hsync_start - m->hdisplay;
+       vm->hback_porch = m->htotal - m->hsync_end;
+       vm->hsync_len = m->hsync_end - m->hsync_start;
 }
 
-static struct exynos_drm_display_ops exynos_dsi_display_ops = {
-       .create_connector = exynos_dsi_create_connector,
+static struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
+       .mode_fixup = exynos_dsi_mode_fixup,
        .mode_set = exynos_dsi_mode_set,
-       .dpms = exynos_dsi_dpms
+       .enable = exynos_dsi_enable,
+       .disable = exynos_dsi_disable,
+};
+
+static struct drm_encoder_funcs exynos_dsi_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
 };
 
 MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
@@ -1821,22 +1815,35 @@ end:
 static int exynos_dsi_bind(struct device *dev, struct device *master,
                                void *data)
 {
-       struct exynos_drm_display *display = dev_get_drvdata(dev);
-       struct exynos_dsi *dsi = display_to_dsi(display);
+       struct drm_encoder *encoder = dev_get_drvdata(dev);
+       struct exynos_dsi *dsi = encoder_to_dsi(encoder);
        struct drm_device *drm_dev = data;
        struct drm_bridge *bridge;
        int ret;
 
-       ret = exynos_drm_create_enc_conn(drm_dev, display);
+       ret = exynos_drm_crtc_get_pipe_from_type(drm_dev,
+                                                 EXYNOS_DISPLAY_TYPE_LCD);
+       if (ret < 0)
+               return ret;
+
+       encoder->possible_crtcs = 1 << ret;
+
+       DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+       drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+
+       drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs);
+
+       ret = exynos_dsi_create_connector(encoder);
        if (ret) {
-               DRM_ERROR("Encoder create [%d] failed with %d\n",
-                         display->type, ret);
+               DRM_ERROR("failed to create connector ret = %d\n", ret);
+               drm_encoder_cleanup(encoder);
                return ret;
        }
 
        bridge = of_drm_find_bridge(dsi->bridge_node);
        if (bridge) {
-               display->encoder->bridge = bridge;
                drm_bridge_attach(drm_dev, bridge);
        }
 
@@ -1846,10 +1853,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 static void exynos_dsi_unbind(struct device *dev, struct device *master,
                                void *data)
 {
-       struct exynos_drm_display *display = dev_get_drvdata(dev);
-       struct exynos_dsi *dsi = display_to_dsi(display);
+       struct drm_encoder *encoder = dev_get_drvdata(dev);
+       struct exynos_dsi *dsi = encoder_to_dsi(encoder);
 
-       exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF);
+       exynos_dsi_disable(encoder);
 
        mipi_dsi_host_unregister(&dsi->dsi_host);
 }
@@ -1870,9 +1877,6 @@ static int exynos_dsi_probe(struct platform_device *pdev)
        if (!dsi)
                return -ENOMEM;
 
-       dsi->display.type = EXYNOS_DISPLAY_TYPE_LCD;
-       dsi->display.ops = &exynos_dsi_display_ops;
-
        /* To be checked as invalid one */
        dsi->te_gpio = -ENOENT;
 
@@ -1948,7 +1952,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)
                return ret;
        }
 
-       platform_set_drvdata(pdev, &dsi->display);
+       platform_set_drvdata(pdev, &dsi->encoder);
 
        return component_add(dev, &exynos_dsi_component_ops);
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
deleted file mode 100644 (file)
index 7b89fd5..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/* exynos_drm_encoder.c
- *
- * 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 "exynos_drm_drv.h"
-#include "exynos_drm_encoder.h"
-
-#define to_exynos_encoder(x)   container_of(x, struct exynos_drm_encoder,\
-                               drm_encoder)
-
-/*
- * exynos specific encoder structure.
- *
- * @drm_encoder: encoder object.
- * @display: the display structure that maps to this encoder
- */
-struct exynos_drm_encoder {
-       struct drm_encoder              drm_encoder;
-       struct exynos_drm_display       *display;
-};
-
-static bool
-exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
-                              const struct drm_display_mode *mode,
-                              struct drm_display_mode *adjusted_mode)
-{
-       struct drm_device *dev = encoder->dev;
-       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_display *display = exynos_encoder->display;
-       struct drm_connector *connector;
-
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (connector->encoder != encoder)
-                       continue;
-
-               if (display->ops->mode_fixup)
-                       display->ops->mode_fixup(display, connector, mode,
-                                       adjusted_mode);
-       }
-
-       return true;
-}
-
-static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
-                                        struct drm_display_mode *mode,
-                                        struct drm_display_mode *adjusted_mode)
-{
-       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_display *display = exynos_encoder->display;
-
-       if (display->ops->mode_set)
-               display->ops->mode_set(display, adjusted_mode);
-}
-
-static void exynos_drm_encoder_enable(struct drm_encoder *encoder)
-{
-       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_display *display = exynos_encoder->display;
-
-       if (display->ops->dpms)
-               display->ops->dpms(display, DRM_MODE_DPMS_ON);
-
-       if (display->ops->commit)
-               display->ops->commit(display);
-}
-
-static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
-{
-       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_display *display = exynos_encoder->display;
-
-       if (display->ops->dpms)
-               display->ops->dpms(display, DRM_MODE_DPMS_OFF);
-}
-
-static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
-       .mode_fixup     = exynos_drm_encoder_mode_fixup,
-       .mode_set       = exynos_drm_encoder_mode_set,
-       .enable         = exynos_drm_encoder_enable,
-       .disable        = exynos_drm_encoder_disable,
-};
-
-static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
-{
-       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-
-       drm_encoder_cleanup(encoder);
-       kfree(exynos_encoder);
-}
-
-static struct drm_encoder_funcs exynos_encoder_funcs = {
-       .destroy = exynos_drm_encoder_destroy,
-};
-
-static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
-{
-       struct drm_encoder *clone;
-       struct drm_device *dev = encoder->dev;
-       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_display *display = exynos_encoder->display;
-       unsigned int clone_mask = 0;
-       int cnt = 0;
-
-       list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
-               switch (display->type) {
-               case EXYNOS_DISPLAY_TYPE_LCD:
-               case EXYNOS_DISPLAY_TYPE_HDMI:
-               case EXYNOS_DISPLAY_TYPE_VIDI:
-                       clone_mask |= (1 << (cnt++));
-                       break;
-               default:
-                       continue;
-               }
-       }
-
-       return clone_mask;
-}
-
-void exynos_drm_encoder_setup(struct drm_device *dev)
-{
-       struct drm_encoder *encoder;
-
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
-               encoder->possible_clones = exynos_drm_encoder_clones(encoder);
-}
-
-struct drm_encoder *
-exynos_drm_encoder_create(struct drm_device *dev,
-                          struct exynos_drm_display *display,
-                          unsigned long possible_crtcs)
-{
-       struct drm_encoder *encoder;
-       struct exynos_drm_encoder *exynos_encoder;
-
-       if (!possible_crtcs)
-               return NULL;
-
-       exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
-       if (!exynos_encoder)
-               return NULL;
-
-       exynos_encoder->display = display;
-       encoder = &exynos_encoder->drm_encoder;
-       encoder->possible_crtcs = possible_crtcs;
-
-       DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
-
-       drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
-                       DRM_MODE_ENCODER_TMDS);
-
-       drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
-
-       DRM_DEBUG_KMS("encoder has been created\n");
-
-       return encoder;
-}
-
-struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder)
-{
-       return to_exynos_encoder(encoder)->display;
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
deleted file mode 100644 (file)
index 26305d8..0000000
+++ /dev/null
@@ -1,23 +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_ENCODER_H_
-#define _EXYNOS_DRM_ENCODER_H_
-
-void exynos_drm_encoder_setup(struct drm_device *dev);
-struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
-                       struct exynos_drm_display *mgr,
-                       unsigned long possible_crtcs);
-struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder);
-
-#endif
index 2b6320e6eae2fa1189693a6f3de159d607d43129..9738f4e0c6eb07d7ac442525e9113a6f774fda06 100644 (file)
@@ -238,22 +238,22 @@ err_free:
        return ERR_PTR(ret);
 }
 
-struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
-                                               int index)
+struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
+                                                int index)
 {
        struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
-       struct exynos_drm_gem_buf *buffer;
+       struct exynos_drm_gem_obj *obj;
 
        if (index >= MAX_FB_BUFFER)
                return NULL;
 
-       buffer = exynos_fb->exynos_gem_obj[index]->buffer;
-       if (!buffer)
+       obj = exynos_fb->exynos_gem_obj[index];
+       if (!obj)
                return NULL;
 
-       DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)buffer->dma_addr);
+       DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)obj->dma_addr);
 
-       return buffer;
+       return obj;
 }
 
 static void exynos_drm_output_poll_changed(struct drm_device *dev)
index 517471b37566cd8b5224720954113865549cf12d..1c9e27c32cd1b230c569cb73fdbff56081bbf660 100644 (file)
@@ -19,8 +19,8 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
                            struct drm_mode_fb_cmd2 *mode_cmd,
                            struct drm_gem_object *obj);
 
-/* get memory information of a drm framebuffer */
-struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
+/* get gem object of a drm framebuffer */
+struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
                                                 int index);
 
 void exynos_drm_mode_config_init(struct drm_device *dev);
index e0b085b4bdfac33d1a8a5a436c8d5764a6fe33e8..624595afbce0ecf077f02a7064a8e2d38cac8e7d 100644 (file)
@@ -40,8 +40,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
 {
        struct drm_fb_helper *helper = info->par;
        struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper);
-       struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
-       struct exynos_drm_gem_buf *buffer = exynos_gem_obj->buffer;
+       struct exynos_drm_gem_obj *obj = exynos_fbd->exynos_gem_obj;
        unsigned long vm_size;
        int ret;
 
@@ -49,11 +48,11 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
 
        vm_size = vma->vm_end - vma->vm_start;
 
-       if (vm_size > buffer->size)
+       if (vm_size > obj->size)
                return -EINVAL;
 
-       ret = dma_mmap_attrs(helper->dev->dev, vma, buffer->pages,
-               buffer->dma_addr, buffer->size, &buffer->dma_attrs);
+       ret = dma_mmap_attrs(helper->dev->dev, vma, obj->pages, obj->dma_addr,
+                            obj->size, &obj->dma_attrs);
        if (ret < 0) {
                DRM_ERROR("failed to mmap.\n");
                return ret;
@@ -65,9 +64,9 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
 static struct fb_ops exynos_drm_fb_ops = {
        .owner          = THIS_MODULE,
        .fb_mmap        = exynos_drm_fb_mmap,
-       .fb_fillrect    = cfb_fillrect,
-       .fb_copyarea    = cfb_copyarea,
-       .fb_imageblit   = cfb_imageblit,
+       .fb_fillrect    = drm_fb_helper_cfb_fillrect,
+       .fb_copyarea    = drm_fb_helper_cfb_copyarea,
+       .fb_imageblit   = drm_fb_helper_cfb_imageblit,
        .fb_check_var   = drm_fb_helper_check_var,
        .fb_set_par     = drm_fb_helper_set_par,
        .fb_blank       = drm_fb_helper_blank,
@@ -80,7 +79,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
                                     struct drm_framebuffer *fb)
 {
        struct fb_info *fbi = helper->fbdev;
-       struct exynos_drm_gem_buf *buffer;
+       struct exynos_drm_gem_obj *obj;
        unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
        unsigned int nr_pages;
        unsigned long offset;
@@ -89,18 +88,17 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
        drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
        /* RGB formats use only one buffer */
-       buffer = exynos_drm_fb_buffer(fb, 0);
-       if (!buffer) {
-               DRM_DEBUG_KMS("buffer is null.\n");
+       obj = exynos_drm_fb_gem_obj(fb, 0);
+       if (!obj) {
+               DRM_DEBUG_KMS("gem object is null.\n");
                return -EFAULT;
        }
 
-       nr_pages = buffer->size >> PAGE_SHIFT;
+       nr_pages = obj->size >> PAGE_SHIFT;
 
-       buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
-                       nr_pages, VM_MAP,
+       obj->kvaddr = (void __iomem *) vmap(obj->pages, nr_pages, VM_MAP,
                        pgprot_writecombine(PAGE_KERNEL));
-       if (!buffer->kvaddr) {
+       if (!obj->kvaddr) {
                DRM_ERROR("failed to map pages to kernel space.\n");
                return -EIO;
        }
@@ -111,7 +109,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
        offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
        offset += fbi->var.yoffset * fb->pitches[0];
 
-       fbi->screen_base = buffer->kvaddr + offset;
+       fbi->screen_base = obj->kvaddr + offset;
        fbi->screen_size = size;
        fbi->fix.smem_len = size;
 
@@ -142,10 +140,10 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
 
        mutex_lock(&dev->struct_mutex);
 
-       fbi = framebuffer_alloc(0, &pdev->dev);
-       if (!fbi) {
+       fbi = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(fbi)) {
                DRM_ERROR("failed to allocate fb info.\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(fbi);
                goto out;
        }
 
@@ -165,7 +163,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
 
        if (IS_ERR(exynos_gem_obj)) {
                ret = PTR_ERR(exynos_gem_obj);
-               goto err_release_framebuffer;
+               goto err_release_fbi;
        }
 
        exynos_fbdev->exynos_gem_obj = exynos_gem_obj;
@@ -178,33 +176,23 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
                goto err_destroy_gem;
        }
 
-       helper->fbdev = fbi;
-
        fbi->par = helper;
        fbi->flags = FBINFO_FLAG_DEFAULT;
        fbi->fbops = &exynos_drm_fb_ops;
 
-       ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
-       if (ret) {
-               DRM_ERROR("failed to allocate cmap.\n");
-               goto err_destroy_framebuffer;
-       }
-
        ret = exynos_drm_fbdev_update(helper, sizes, helper->fb);
        if (ret < 0)
-               goto err_dealloc_cmap;
+               goto err_destroy_framebuffer;
 
        mutex_unlock(&dev->struct_mutex);
        return ret;
 
-err_dealloc_cmap:
-       fb_dealloc_cmap(&fbi->cmap);
 err_destroy_framebuffer:
        drm_framebuffer_cleanup(helper->fb);
 err_destroy_gem:
        exynos_drm_gem_destroy(exynos_gem_obj);
-err_release_framebuffer:
-       framebuffer_release(fbi);
+err_release_fbi:
+       drm_fb_helper_release_fbi(helper);
 
 /*
  * if failed, all resources allocated above would be released by
@@ -300,8 +288,8 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
        struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
        struct drm_framebuffer *fb;
 
-       if (exynos_gem_obj->buffer->kvaddr)
-               vunmap(exynos_gem_obj->buffer->kvaddr);
+       if (exynos_gem_obj->kvaddr)
+               vunmap(exynos_gem_obj->kvaddr);
 
        /* release drm framebuffer and real buffer */
        if (fb_helper->fb && fb_helper->fb->funcs) {
@@ -312,21 +300,8 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
                }
        }
 
-       /* release linux framebuffer */
-       if (fb_helper->fbdev) {
-               struct fb_info *info;
-               int ret;
-
-               info = fb_helper->fbdev;
-               ret = unregister_framebuffer(info);
-               if (ret < 0)
-                       DRM_DEBUG_KMS("failed unregister_framebuffer()\n");
-
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(fb_helper);
+       drm_fb_helper_release_fbi(fb_helper);
 
        drm_fb_helper_fini(fb_helper);
 }
index 842d6b8dc3c435ee7d836402d4169847aef75d31..2a652359af644b51f257cde7528d70b6016897da 100644 (file)
@@ -1745,7 +1745,6 @@ static int fimc_probe(struct platform_device *pdev)
        spin_lock_init(&ctx->lock);
        platform_set_drvdata(pdev, ctx);
 
-       pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
 
        ret = exynos_drm_ippdrv_register(ippdrv);
index 794e56c8798e797fbc5d5b72944a9f12ed4a34a4..5def6bc073ebb222ea4656a865108efd557a0eb2 100644 (file)
@@ -169,7 +169,7 @@ struct fimd_context {
 
        struct exynos_drm_panel_info panel;
        struct fimd_driver_data *driver_data;
-       struct exynos_drm_display *display;
+       struct drm_encoder *encoder;
 };
 
 static const struct of_device_id fimd_driver_dt_match[] = {
@@ -348,13 +348,6 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc)
        pm_runtime_put(ctx->dev);
 }
 
-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))
-               drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
-}
-
 static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
                const struct drm_display_mode *mode)
 {
@@ -486,9 +479,9 @@ static void fimd_commit(struct exynos_drm_crtc *crtc)
 }
 
 
-static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
+static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
+                               struct drm_framebuffer *fb)
 {
-       struct exynos_drm_plane *plane = &ctx->planes[win];
        unsigned long val;
 
        val = WINCONx_ENWIN;
@@ -498,11 +491,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 (plane->pixel_format == DRM_FORMAT_ARGB8888)
-                       plane->pixel_format = DRM_FORMAT_XRGB8888;
+               if (fb->pixel_format == DRM_FORMAT_ARGB8888)
+                       fb->pixel_format = DRM_FORMAT_XRGB8888;
        }
 
-       switch (plane->pixel_format) {
+       switch (fb->pixel_format) {
        case DRM_FORMAT_C8:
                val |= WINCON0_BPPMODE_8BPP_PALETTE;
                val |= WINCONx_BURSTLEN_8WORD;
@@ -538,7 +531,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
                break;
        }
 
-       DRM_DEBUG_KMS("bpp = %d\n", plane->bpp);
+       DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel);
 
        /*
         * In case of exynos, setting dma-burst to 16Word causes permanent
@@ -548,7 +541,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
         * movement causes unstable DMA which results into iommu crash/tear.
         */
 
-       if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+       if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
                val &= ~WINCONx_BURSTLEN_MASK;
                val |= WINCONx_BURSTLEN_4WORD;
        }
@@ -614,21 +607,17 @@ 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, unsigned int win)
+static void fimd_update_plane(struct exynos_drm_crtc *crtc,
+                             struct exynos_drm_plane *plane)
 {
        struct fimd_context *ctx = crtc->ctx;
-       struct exynos_drm_plane *plane;
+       struct drm_plane_state *state = plane->base.state;
        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 < 0 || win >= WINDOWS_NR)
-               return;
-
-       plane = &ctx->planes[win];
+       unsigned int win = plane->zpos;
+       unsigned int bpp = state->fb->bits_per_pixel >> 3;
+       unsigned int pitch = state->fb->pitches[0];
 
        if (ctx->suspended)
                return;
@@ -647,8 +636,8 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
        fimd_shadow_protect_win(ctx, win, true);
 
 
-       offset = plane->src_x * (plane->bpp >> 3);
-       offset += plane->src_y * plane->pitch;
+       offset = plane->src_x * bpp;
+       offset += plane->src_y * pitch;
 
        /* buffer start address */
        dma_addr = plane->dma_addr[0] + offset;
@@ -656,18 +645,18 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
        writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
 
        /* buffer end address */
-       size = plane->pitch * plane->crtc_height;
+       size = pitch * plane->crtc_h;
        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)dma_addr, val, size);
        DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       plane->crtc_width, plane->crtc_height);
+                       plane->crtc_w, plane->crtc_h);
 
        /* buffer size */
-       buf_offsize = plane->pitch - (plane->crtc_width * (plane->bpp >> 3));
-       line_size = plane->crtc_width * (plane->bpp >> 3);
+       buf_offsize = pitch - (plane->crtc_w * bpp);
+       line_size = plane->crtc_w * bpp;
        val = VIDW_BUF_SIZE_OFFSET(buf_offsize) |
                VIDW_BUF_SIZE_PAGEWIDTH(line_size) |
                VIDW_BUF_SIZE_OFFSET_E(buf_offsize) |
@@ -681,10 +670,10 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
                VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y);
        writel(val, ctx->regs + VIDOSD_A(win));
 
-       last_x = plane->crtc_x + plane->crtc_width;
+       last_x = plane->crtc_x + plane->crtc_w;
        if (last_x)
                last_x--;
-       last_y = plane->crtc_y + plane->crtc_height;
+       last_y = plane->crtc_y + plane->crtc_h;
        if (last_y)
                last_y--;
 
@@ -701,13 +690,13 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
                u32 offset = VIDOSD_D(win);
                if (win == 0)
                        offset = VIDOSD_C(win);
-               val = plane->crtc_width * plane->crtc_height;
+               val = plane->crtc_w * plane->crtc_h;
                writel(val, ctx->regs + offset);
 
                DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
        }
 
-       fimd_win_set_pixfmt(ctx, win);
+       fimd_win_set_pixfmt(ctx, win, state->fb);
 
        /* hardware window 0 doesn't support color key. */
        if (win != 0)
@@ -725,15 +714,11 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
                atomic_set(&ctx->win_updated, 1);
 }
 
-static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
+static void fimd_disable_plane(struct exynos_drm_crtc *crtc,
+                              struct exynos_drm_plane *plane)
 {
        struct fimd_context *ctx = crtc->ctx;
-       struct exynos_drm_plane *plane;
-
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-       plane = &ctx->planes[win];
+       unsigned int win = plane->zpos;
 
        if (ctx->suspended)
                return;
@@ -795,7 +780,7 @@ static void fimd_disable(struct exynos_drm_crtc *crtc)
         * a destroyed buffer later.
         */
        for (i = 0; i < WINDOWS_NR; i++)
-               fimd_win_disable(crtc, i);
+               fimd_disable_plane(crtc, &ctx->planes[i]);
 
        fimd_enable_vblank(crtc);
        fimd_wait_for_vblank(crtc);
@@ -862,7 +847,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc)
        }
 
        if (test_bit(0, &ctx->irq_flags))
-               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+               drm_crtc_handle_vblank(&ctx->crtc->base);
 }
 
 static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable)
@@ -890,11 +875,10 @@ static const 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_commit = fimd_win_commit,
-       .win_disable = fimd_win_disable,
+       .update_plane = fimd_update_plane,
+       .disable_plane = fimd_disable_plane,
        .te_handler = fimd_te_handler,
        .clock_enable = fimd_dp_clock_enable,
-       .clear_channels = fimd_clear_channels,
 };
 
 static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
@@ -913,13 +897,13 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
                goto out;
 
        if (ctx->i80_if) {
-               exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+               exynos_drm_crtc_finish_pageflip(ctx->crtc);
 
                /* Exits triggering mode */
                atomic_set(&ctx->triggering, 0);
        } else {
-               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
-               exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+               drm_crtc_handle_vblank(&ctx->crtc->base);
+               exynos_drm_crtc_finish_pageflip(ctx->crtc);
 
                /* set wait vsync event to zero and wake up queue. */
                if (atomic_read(&ctx->wait_vsync_event)) {
@@ -961,10 +945,13 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
        if (IS_ERR(ctx->crtc))
                return PTR_ERR(ctx->crtc);
 
-       if (ctx->display)
-               exynos_drm_create_enc_conn(drm_dev, ctx->display);
+       if (ctx->encoder)
+               exynos_dpi_bind(drm_dev, ctx->encoder);
+
+       if (is_drm_iommu_supported(drm_dev))
+               fimd_clear_channels(ctx->crtc);
 
-       ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev);
+       ret = drm_iommu_attach_device(drm_dev, dev);
        if (ret)
                priv->pipe--;
 
@@ -978,10 +965,10 @@ static void fimd_unbind(struct device *dev, struct device *master,
 
        fimd_disable(ctx->crtc);
 
-       fimd_iommu_detach_devices(ctx);
+       drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
 
-       if (ctx->display)
-               exynos_dpi_remove(ctx->display);
+       if (ctx->encoder)
+               exynos_dpi_remove(ctx->encoder);
 }
 
 static const struct component_ops fimd_component_ops = {
@@ -1088,10 +1075,9 @@ static int fimd_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ctx);
 
-       ctx->display = exynos_dpi_probe(dev);
-       if (IS_ERR(ctx->display)) {
-               return PTR_ERR(ctx->display);
-       }
+       ctx->encoder = exynos_dpi_probe(dev);
+       if (IS_ERR(ctx->encoder))
+               return PTR_ERR(ctx->encoder);
 
        pm_runtime_enable(dev);
 
index 81a25083080845d626c6b50b2f46a9c4897e79f3..ba008391a2fcceddfa78713856fde689df172b56 100644 (file)
@@ -1319,9 +1319,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
                return ret;
        }
 
-       if (!is_drm_iommu_supported(drm_dev))
-               return 0;
-
        ret = drm_iommu_attach_device(drm_dev, dev);
        if (ret < 0) {
                dev_err(dev, "failed to enable iommu.\n");
@@ -1334,9 +1331,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
 
 static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
 {
-       if (!is_drm_iommu_supported(drm_dev))
-               return;
-
        drm_iommu_detach_device(drm_dev, dev);
 }
 
index 0d5b9698d38402d912304b3915e95e37bd207978..67461b77f0401c989599897909bc3106273bb372 100644 (file)
 #include <drm/drm_vma_manager.h>
 
 #include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_gem.h"
-#include "exynos_drm_buf.h"
 #include "exynos_drm_iommu.h"
 
-static unsigned int convert_to_vm_err_msg(int msg)
+static int exynos_drm_alloc_buf(struct exynos_drm_gem_obj *obj)
 {
-       unsigned int out_msg;
+       struct drm_device *dev = obj->base.dev;
+       enum dma_attr attr;
+       unsigned int nr_pages;
 
-       switch (msg) {
-       case 0:
-       case -ERESTARTSYS:
-       case -EINTR:
-               out_msg = VM_FAULT_NOPAGE;
-               break;
+       if (obj->dma_addr) {
+               DRM_DEBUG_KMS("already allocated.\n");
+               return 0;
+       }
 
-       case -ENOMEM:
-               out_msg = VM_FAULT_OOM;
-               break;
+       init_dma_attrs(&obj->dma_attrs);
 
-       default:
-               out_msg = VM_FAULT_SIGBUS;
-               break;
-       }
+       /*
+        * if EXYNOS_BO_CONTIG, fully physically contiguous memory
+        * region will be allocated else physically contiguous
+        * as possible.
+        */
+       if (!(obj->flags & EXYNOS_BO_NONCONTIG))
+               dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &obj->dma_attrs);
 
-       return out_msg;
-}
+       /*
+        * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
+        * else cachable mapping.
+        */
+       if (obj->flags & EXYNOS_BO_WC || !(obj->flags & EXYNOS_BO_CACHABLE))
+               attr = DMA_ATTR_WRITE_COMBINE;
+       else
+               attr = DMA_ATTR_NON_CONSISTENT;
 
-static int check_gem_flags(unsigned int flags)
-{
-       if (flags & ~(EXYNOS_BO_MASK)) {
-               DRM_ERROR("invalid flags.\n");
-               return -EINVAL;
-       }
+       dma_set_attr(attr, &obj->dma_attrs);
+       dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &obj->dma_attrs);
 
-       return 0;
-}
+       nr_pages = obj->size >> PAGE_SHIFT;
 
-static void update_vm_cache_attr(struct exynos_drm_gem_obj *obj,
-                                       struct vm_area_struct *vma)
-{
-       DRM_DEBUG_KMS("flags = 0x%x\n", obj->flags);
+       if (!is_drm_iommu_supported(dev)) {
+               dma_addr_t start_addr;
+               unsigned int i = 0;
 
-       /* non-cachable as default. */
-       if (obj->flags & EXYNOS_BO_CACHABLE)
-               vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
-       else if (obj->flags & EXYNOS_BO_WC)
-               vma->vm_page_prot =
-                       pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
-       else
-               vma->vm_page_prot =
-                       pgprot_noncached(vm_get_page_prot(vma->vm_flags));
-}
+               obj->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
+               if (!obj->pages) {
+                       DRM_ERROR("failed to allocate pages.\n");
+                       return -ENOMEM;
+               }
 
-static unsigned long roundup_gem_size(unsigned long size, unsigned int flags)
-{
-       /* TODO */
+               obj->cookie = dma_alloc_attrs(dev->dev,
+                                       obj->size,
+                                       &obj->dma_addr, GFP_KERNEL,
+                                       &obj->dma_attrs);
+               if (!obj->cookie) {
+                       DRM_ERROR("failed to allocate buffer.\n");
+                       drm_free_large(obj->pages);
+                       return -ENOMEM;
+               }
+
+               start_addr = obj->dma_addr;
+               while (i < nr_pages) {
+                       obj->pages[i] = phys_to_page(start_addr);
+                       start_addr += PAGE_SIZE;
+                       i++;
+               }
+       } else {
+               obj->pages = dma_alloc_attrs(dev->dev, obj->size,
+                                       &obj->dma_addr, GFP_KERNEL,
+                                       &obj->dma_attrs);
+               if (!obj->pages) {
+                       DRM_ERROR("failed to allocate buffer.\n");
+                       return -ENOMEM;
+               }
+       }
+
+       DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
+                       (unsigned long)obj->dma_addr,
+                       obj->size);
 
-       return roundup(size, PAGE_SIZE);
+       return 0;
 }
 
-static int exynos_drm_gem_map_buf(struct drm_gem_object *obj,
-                                       struct vm_area_struct *vma,
-                                       unsigned long f_vaddr,
-                                       pgoff_t page_offset)
+static void exynos_drm_free_buf(struct exynos_drm_gem_obj *obj)
 {
-       struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
-       struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
-       struct scatterlist *sgl;
-       unsigned long pfn;
-       int i;
-
-       if (!buf->sgt)
-               return -EINTR;
+       struct drm_device *dev = obj->base.dev;
 
-       if (page_offset >= (buf->size >> PAGE_SHIFT)) {
-               DRM_ERROR("invalid page offset\n");
-               return -EINVAL;
+       if (!obj->dma_addr) {
+               DRM_DEBUG_KMS("dma_addr is invalid.\n");
+               return;
        }
 
-       sgl = buf->sgt->sgl;
-       for_each_sg(buf->sgt->sgl, sgl, buf->sgt->nents, i) {
-               if (page_offset < (sgl->length >> PAGE_SHIFT))
-                       break;
-               page_offset -=  (sgl->length >> PAGE_SHIFT);
-       }
+       DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
+                       (unsigned long)obj->dma_addr, obj->size);
 
-       pfn = __phys_to_pfn(sg_phys(sgl)) + page_offset;
+       if (!is_drm_iommu_supported(dev)) {
+               dma_free_attrs(dev->dev, obj->size, obj->cookie,
+                               (dma_addr_t)obj->dma_addr, &obj->dma_attrs);
+               drm_free_large(obj->pages);
+       } else
+               dma_free_attrs(dev->dev, obj->size, obj->pages,
+                               (dma_addr_t)obj->dma_addr, &obj->dma_attrs);
 
-       return vm_insert_mixed(vma, f_vaddr, pfn);
+       obj->dma_addr = (dma_addr_t)NULL;
 }
 
 static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
@@ -131,11 +145,7 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
 
 void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
 {
-       struct drm_gem_object *obj;
-       struct exynos_drm_gem_buf *buf;
-
-       obj = &exynos_gem_obj->base;
-       buf = exynos_gem_obj->buffer;
+       struct drm_gem_object *obj = &exynos_gem_obj->base;
 
        DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count);
 
@@ -148,12 +158,9 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
        if (obj->import_attach)
                goto out;
 
-       exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags, buf);
+       exynos_drm_free_buf(exynos_gem_obj);
 
 out:
-       exynos_drm_fini_buf(obj->dev, buf);
-       exynos_gem_obj->buffer = NULL;
-
        drm_gem_free_mmap_offset(obj);
 
        /* release file pointer to gem object. */
@@ -180,7 +187,7 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
 
        drm_gem_object_unreference_unlocked(obj);
 
-       return exynos_gem_obj->buffer->size;
+       return exynos_gem_obj->size;
 }
 
 
@@ -193,7 +200,7 @@ struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
 
        exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL);
        if (!exynos_gem_obj)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        exynos_gem_obj->size = size;
        obj = &exynos_gem_obj->base;
@@ -202,7 +209,7 @@ struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
        if (ret < 0) {
                DRM_ERROR("failed to initialize gem object\n");
                kfree(exynos_gem_obj);
-               return NULL;
+               return ERR_PTR(ret);
        }
 
        DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
@@ -215,47 +222,35 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
                                                unsigned long size)
 {
        struct exynos_drm_gem_obj *exynos_gem_obj;
-       struct exynos_drm_gem_buf *buf;
        int ret;
 
+       if (flags & ~(EXYNOS_BO_MASK)) {
+               DRM_ERROR("invalid flags.\n");
+               return ERR_PTR(-EINVAL);
+       }
+
        if (!size) {
                DRM_ERROR("invalid size.\n");
                return ERR_PTR(-EINVAL);
        }
 
-       size = roundup_gem_size(size, flags);
-
-       ret = check_gem_flags(flags);
-       if (ret)
-               return ERR_PTR(ret);
-
-       buf = exynos_drm_init_buf(dev, size);
-       if (!buf)
-               return ERR_PTR(-ENOMEM);
+       size = roundup(size, PAGE_SIZE);
 
        exynos_gem_obj = exynos_drm_gem_init(dev, size);
-       if (!exynos_gem_obj) {
-               ret = -ENOMEM;
-               goto err_fini_buf;
-       }
-
-       exynos_gem_obj->buffer = buf;
+       if (IS_ERR(exynos_gem_obj))
+               return exynos_gem_obj;
 
        /* set memory type and cache attribute from user side. */
        exynos_gem_obj->flags = flags;
 
-       ret = exynos_drm_alloc_buf(dev, buf, flags);
-       if (ret < 0)
-               goto err_gem_fini;
+       ret = exynos_drm_alloc_buf(exynos_gem_obj);
+       if (ret < 0) {
+               drm_gem_object_release(&exynos_gem_obj->base);
+               kfree(exynos_gem_obj);
+               return ERR_PTR(ret);
+       }
 
        return exynos_gem_obj;
-
-err_gem_fini:
-       drm_gem_object_release(&exynos_gem_obj->base);
-       kfree(exynos_gem_obj);
-err_fini_buf:
-       exynos_drm_fini_buf(dev, buf);
-       return ERR_PTR(ret);
 }
 
 int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
@@ -294,7 +289,7 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
 
        exynos_gem_obj = to_exynos_gem_obj(obj);
 
-       return &exynos_gem_obj->buffer->dma_addr;
+       return &exynos_gem_obj->dma_addr;
 }
 
 void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
@@ -322,7 +317,6 @@ int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj,
                                      struct vm_area_struct *vma)
 {
        struct drm_device *drm_dev = exynos_gem_obj->base.dev;
-       struct exynos_drm_gem_buf *buffer;
        unsigned long vm_size;
        int ret;
 
@@ -331,19 +325,13 @@ int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj,
 
        vm_size = vma->vm_end - vma->vm_start;
 
-       /*
-        * a buffer contains information to physically continuous memory
-        * allocated by user request or at framebuffer creation.
-        */
-       buffer = exynos_gem_obj->buffer;
-
        /* check if user-requested size is valid. */
-       if (vm_size > buffer->size)
+       if (vm_size > exynos_gem_obj->size)
                return -EINVAL;
 
-       ret = dma_mmap_attrs(drm_dev->dev, vma, buffer->pages,
-                               buffer->dma_addr, buffer->size,
-                               &buffer->dma_attrs);
+       ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem_obj->pages,
+                               exynos_gem_obj->dma_addr, exynos_gem_obj->size,
+                               &exynos_gem_obj->dma_attrs);
        if (ret < 0) {
                DRM_ERROR("failed to mmap.\n");
                return ret;
@@ -503,15 +491,6 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
 
 void exynos_drm_gem_free_object(struct drm_gem_object *obj)
 {
-       struct exynos_drm_gem_obj *exynos_gem_obj;
-       struct exynos_drm_gem_buf *buf;
-
-       exynos_gem_obj = to_exynos_gem_obj(obj);
-       buf = exynos_gem_obj->buffer;
-
-       if (obj->import_attach)
-               drm_prime_gem_destroy(obj, buf->sgt);
-
        exynos_drm_gem_destroy(to_exynos_gem_obj(obj));
 }
 
@@ -595,24 +574,34 @@ unlock:
 int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct drm_gem_object *obj = vma->vm_private_data;
-       struct drm_device *dev = obj->dev;
-       unsigned long f_vaddr;
+       struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+       unsigned long pfn;
        pgoff_t page_offset;
        int ret;
 
        page_offset = ((unsigned long)vmf->virtual_address -
                        vma->vm_start) >> PAGE_SHIFT;
-       f_vaddr = (unsigned long)vmf->virtual_address;
-
-       mutex_lock(&dev->struct_mutex);
 
-       ret = exynos_drm_gem_map_buf(obj, vma, f_vaddr, page_offset);
-       if (ret < 0)
-               DRM_ERROR("failed to map a buffer with user.\n");
+       if (page_offset >= (exynos_gem_obj->size >> PAGE_SHIFT)) {
+               DRM_ERROR("invalid page offset\n");
+               ret = -EINVAL;
+               goto out;
+       }
 
-       mutex_unlock(&dev->struct_mutex);
+       pfn = page_to_pfn(exynos_gem_obj->pages[page_offset]);
+       ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
 
-       return convert_to_vm_err_msg(ret);
+out:
+       switch (ret) {
+       case 0:
+       case -ERESTARTSYS:
+       case -EINTR:
+               return VM_FAULT_NOPAGE;
+       case -ENOMEM:
+               return VM_FAULT_OOM;
+       default:
+               return VM_FAULT_SIGBUS;
+       }
 }
 
 int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
@@ -631,11 +620,17 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        obj = vma->vm_private_data;
        exynos_gem_obj = to_exynos_gem_obj(obj);
 
-       ret = check_gem_flags(exynos_gem_obj->flags);
-       if (ret)
-               goto err_close_vm;
+       DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem_obj->flags);
 
-       update_vm_cache_attr(exynos_gem_obj, vma);
+       /* non-cachable as default. */
+       if (exynos_gem_obj->flags & EXYNOS_BO_CACHABLE)
+               vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+       else if (exynos_gem_obj->flags & EXYNOS_BO_WC)
+               vma->vm_page_prot =
+                       pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+       else
+               vma->vm_page_prot =
+                       pgprot_noncached(vm_get_page_prot(vma->vm_flags));
 
        ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma);
        if (ret)
@@ -649,3 +644,76 @@ err_close_vm:
 
        return ret;
 }
+
+/* low-level interface prime helpers */
+struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+       struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+       int npages;
+
+       npages = exynos_gem_obj->size >> PAGE_SHIFT;
+
+       return drm_prime_pages_to_sg(exynos_gem_obj->pages, npages);
+}
+
+struct drm_gem_object *
+exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
+                                    struct dma_buf_attachment *attach,
+                                    struct sg_table *sgt)
+{
+       struct exynos_drm_gem_obj *exynos_gem_obj;
+       int npages;
+       int ret;
+
+       exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size);
+       if (IS_ERR(exynos_gem_obj)) {
+               ret = PTR_ERR(exynos_gem_obj);
+               goto err;
+       }
+
+       exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl);
+
+       npages = exynos_gem_obj->size >> PAGE_SHIFT;
+       exynos_gem_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
+       if (!exynos_gem_obj->pages) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem_obj->pages, NULL,
+                       npages);
+       if (ret < 0)
+               goto err_free_large;
+
+       if (sgt->nents == 1) {
+               /* always physically continuous memory if sgt->nents is 1. */
+               exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
+       } else {
+               /*
+                * this case could be CONTIG or NONCONTIG type but for now
+                * sets NONCONTIG.
+                * TODO. we have to find a way that exporter can notify
+                * the type of its own buffer to importer.
+                */
+               exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
+       }
+
+       return &exynos_gem_obj->base;
+
+err_free_large:
+       drm_free_large(exynos_gem_obj->pages);
+err:
+       drm_gem_object_release(&exynos_gem_obj->base);
+       kfree(exynos_gem_obj);
+       return ERR_PTR(ret);
+}
+
+void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj)
+{
+       return NULL;
+}
+
+void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+       /* Nothing to do */
+}
index 6f42e224828890cd116b2d32c40bf4daf329adc4..cd62f8410d1e5d86f6dd221aebf924be1fe71db9 100644 (file)
 
 #define IS_NONCONTIG_BUFFER(f)         (f & EXYNOS_BO_NONCONTIG)
 
-/*
- * exynos drm gem buffer structure.
- *
- * @cookie: cookie returned by dma_alloc_attrs
- * @kvaddr: kernel virtual address to allocated memory region.
- * *userptr: user space address.
- * @dma_addr: bus address(accessed by dma) to allocated memory region.
- *     - this address could be physical address without IOMMU and
- *     device address with IOMMU.
- * @write: whether pages will be written to by the caller.
- * @pages: Array of backing pages.
- * @sgt: sg table to transfer page data.
- * @size: size of allocated memory region.
- * @pfnmap: indicate whether memory region from userptr is mmaped with
- *     VM_PFNMAP or not.
- */
-struct exynos_drm_gem_buf {
-       void                    *cookie;
-       void __iomem            *kvaddr;
-       unsigned long           userptr;
-       dma_addr_t              dma_addr;
-       struct dma_attrs        dma_attrs;
-       unsigned int            write;
-       struct page             **pages;
-       struct sg_table         *sgt;
-       unsigned long           size;
-       bool                    pfnmap;
-};
-
 /*
  * exynos drm buffer structure.
  *
@@ -59,18 +30,28 @@ struct exynos_drm_gem_buf {
  *     by user request or at framebuffer creation.
  *     continuous memory region allocated by user request
  *     or at framebuffer creation.
+ * @flags: indicate memory type to allocated buffer and cache attruibute.
  * @size: size requested from user, in bytes and this size is aligned
  *     in page unit.
- * @flags: indicate memory type to allocated buffer and cache attruibute.
+ * @cookie: cookie returned by dma_alloc_attrs
+ * @kvaddr: kernel virtual address to allocated memory region.
+ * @dma_addr: bus address(accessed by dma) to allocated memory region.
+ *     - this address could be physical address without IOMMU and
+ *     device address with IOMMU.
+ * @pages: Array of backing pages.
  *
  * P.S. this object would be transferred to user as kms_bo.handle so
  *     user can access the buffer through kms_bo.handle.
  */
 struct exynos_drm_gem_obj {
-       struct drm_gem_object           base;
-       struct exynos_drm_gem_buf       *buffer;
-       unsigned long                   size;
-       unsigned int                    flags;
+       struct drm_gem_object   base;
+       unsigned int            flags;
+       unsigned long           size;
+       void                    *cookie;
+       void __iomem            *kvaddr;
+       dma_addr_t              dma_addr;
+       struct dma_attrs        dma_attrs;
+       struct page             **pages;
 };
 
 struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
@@ -177,4 +158,13 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
                                struct sg_table *sgt,
                                enum dma_data_direction dir);
 
+/* low-level interface prime helpers */
+struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj);
+struct drm_gem_object *
+exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
+                                    struct dma_buf_attachment *attach,
+                                    struct sg_table *sgt);
+void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj);
+void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+
 #endif
index 8040ed2a831f9a6f226baf8aee3ce00b213be8e6..808a0a013780e1ad2bde35623f6f48468d29a7c7 100644 (file)
@@ -582,9 +582,17 @@ static int gsc_src_set_transf(struct device *dev,
                break;
        case EXYNOS_DRM_DEGREE_180:
                cfg |= GSC_IN_ROT_180;
+               if (flip & EXYNOS_DRM_FLIP_VERTICAL)
+                       cfg &= ~GSC_IN_ROT_XFLIP;
+               if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
+                       cfg &= ~GSC_IN_ROT_YFLIP;
                break;
        case EXYNOS_DRM_DEGREE_270:
                cfg |= GSC_IN_ROT_270;
+               if (flip & EXYNOS_DRM_FLIP_VERTICAL)
+                       cfg &= ~GSC_IN_ROT_XFLIP;
+               if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
+                       cfg &= ~GSC_IN_ROT_YFLIP;
                break;
        default:
                dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
@@ -593,8 +601,7 @@ static int gsc_src_set_transf(struct device *dev,
 
        gsc_write(cfg, GSC_IN_CON);
 
-       ctx->rotation = cfg &
-               (GSC_IN_ROT_90 | GSC_IN_ROT_270) ? 1 : 0;
+       ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;
        *swap = ctx->rotation;
 
        return 0;
@@ -846,9 +853,17 @@ static int gsc_dst_set_transf(struct device *dev,
                break;
        case EXYNOS_DRM_DEGREE_180:
                cfg |= GSC_IN_ROT_180;
+               if (flip & EXYNOS_DRM_FLIP_VERTICAL)
+                       cfg &= ~GSC_IN_ROT_XFLIP;
+               if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
+                       cfg &= ~GSC_IN_ROT_YFLIP;
                break;
        case EXYNOS_DRM_DEGREE_270:
                cfg |= GSC_IN_ROT_270;
+               if (flip & EXYNOS_DRM_FLIP_VERTICAL)
+                       cfg &= ~GSC_IN_ROT_XFLIP;
+               if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
+                       cfg &= ~GSC_IN_ROT_YFLIP;
                break;
        default:
                dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
@@ -857,8 +872,7 @@ static int gsc_dst_set_transf(struct device *dev,
 
        gsc_write(cfg, GSC_IN_CON);
 
-       ctx->rotation = cfg &
-               (GSC_IN_ROT_90 | GSC_IN_ROT_270) ? 1 : 0;
+       ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;
        *swap = ctx->rotation;
 
        return 0;
index d4ec7465e9ccdcaa7ebf633d44e3e213a192d356..055e8ec2ef212e831f4eaccf6ecfc3bd7ac76ba0 100644 (file)
@@ -87,10 +87,8 @@ int drm_iommu_attach_device(struct drm_device *drm_dev,
        struct device *dev = drm_dev->dev;
        int ret;
 
-       if (!dev->archdata.mapping) {
-               DRM_ERROR("iommu_mapping is null.\n");
-               return -EFAULT;
-       }
+       if (!dev->archdata.mapping)
+               return 0;
 
        subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev,
                                        sizeof(*subdrv_dev->dma_parms),
@@ -144,17 +142,3 @@ void drm_iommu_detach_device(struct drm_device *drm_dev,
        iommu_detach_device(mapping->domain, subdrv_dev);
        drm_release_iommu_mapping(drm_dev);
 }
-
-int drm_iommu_attach_device_if_possible(struct exynos_drm_crtc *exynos_crtc,
-                       struct drm_device *drm_dev, struct device *subdrv_dev)
-{
-       int ret = 0;
-
-       if (is_drm_iommu_supported(drm_dev)) {
-               if (exynos_crtc->ops->clear_channels)
-                       exynos_crtc->ops->clear_channels(exynos_crtc);
-               return drm_iommu_attach_device(drm_dev, subdrv_dev);
-       }
-
-       return ret;
-}
index 8341c7a475b4e4eaa60e464eb4e2a9306995b83b..dc1b5441f4911be18f197a415d4de9fc9151636c 100644 (file)
@@ -29,19 +29,11 @@ void drm_iommu_detach_device(struct drm_device *dev_dev,
 
 static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
 {
-#ifdef CONFIG_ARM_DMA_USE_IOMMU
        struct device *dev = drm_dev->dev;
 
        return dev->archdata.mapping ? true : false;
-#else
-       return false;
-#endif
 }
 
-int drm_iommu_attach_device_if_possible(
-               struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev,
-               struct device *subdrv_dev);
-
 #else
 
 static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
@@ -69,12 +61,5 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
        return false;
 }
 
-static inline int drm_iommu_attach_device_if_possible(
-               struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev,
-               struct device *subdrv_dev)
-{
-       return 0;
-}
-
 #endif
 #endif
index 67e5451e066feff91e04d27c58929fa36fa787bf..67d24236e745c4dd1cc014ba0c5386784d3441f8 100644 (file)
@@ -1622,12 +1622,10 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
                INIT_LIST_HEAD(&ippdrv->cmd_list);
                mutex_init(&ippdrv->cmd_lock);
 
-               if (is_drm_iommu_supported(drm_dev)) {
-                       ret = drm_iommu_attach_device(drm_dev, ippdrv->dev);
-                       if (ret) {
-                               DRM_ERROR("failed to activate iommu\n");
-                               goto err;
-                       }
+               ret = drm_iommu_attach_device(drm_dev, ippdrv->dev);
+               if (ret) {
+                       DRM_ERROR("failed to activate iommu\n");
+                       goto err;
                }
        }
 
@@ -1637,8 +1635,7 @@ err:
        /* get ipp driver entry */
        list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list,
                                                drv_list) {
-               if (is_drm_iommu_supported(drm_dev))
-                       drm_iommu_detach_device(drm_dev, ippdrv->dev);
+               drm_iommu_detach_device(drm_dev, ippdrv->dev);
 
                ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock,
                                ippdrv->prop_list.ipp_id);
@@ -1654,8 +1651,7 @@ static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
 
        /* get ipp driver entry */
        list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) {
-               if (is_drm_iommu_supported(drm_dev))
-                       drm_iommu_detach_device(drm_dev, ippdrv->dev);
+               drm_iommu_detach_device(drm_dev, ippdrv->dev);
 
                ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock,
                                ippdrv->prop_list.ipp_id);
index a729980d3c2f182a392c55f1f41345c8b19c3fe7..d9a68fd83120a5e35164fa5e5df5c03badfed7b5 100644 (file)
@@ -97,29 +97,18 @@ static void exynos_plane_mode_set(struct drm_plane *plane,
        /* set drm framebuffer data. */
        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->bpp = fb->bits_per_pixel;
-       exynos_plane->pitch = fb->pitches[0];
-       exynos_plane->pixel_format = fb->pixel_format;
+       exynos_plane->src_w = (actual_w * exynos_plane->h_ratio) >> 16;
+       exynos_plane->src_h = (actual_h * exynos_plane->v_ratio) >> 16;
 
        /* set plane range to be displayed. */
        exynos_plane->crtc_x = crtc_x;
        exynos_plane->crtc_y = crtc_y;
-       exynos_plane->crtc_width = actual_w;
-       exynos_plane->crtc_height = actual_h;
-
-       /* set drm mode data. */
-       exynos_plane->mode_width = mode->hdisplay;
-       exynos_plane->mode_height = mode->vdisplay;
-       exynos_plane->refresh = mode->vrefresh;
-       exynos_plane->scan_flag = mode->flags;
+       exynos_plane->crtc_w = actual_w;
+       exynos_plane->crtc_h = actual_h;
 
        DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)",
                        exynos_plane->crtc_x, exynos_plane->crtc_y,
-                       exynos_plane->crtc_width, exynos_plane->crtc_height);
+                       exynos_plane->crtc_w, exynos_plane->crtc_h);
 
        plane->crtc = crtc;
 }
@@ -145,15 +134,15 @@ static int exynos_plane_atomic_check(struct drm_plane *plane,
 
        nr = exynos_drm_fb_get_buf_cnt(state->fb);
        for (i = 0; i < nr; i++) {
-               struct exynos_drm_gem_buf *buffer =
-                                       exynos_drm_fb_buffer(state->fb, i);
+               struct exynos_drm_gem_obj *obj =
+                                       exynos_drm_fb_gem_obj(state->fb, i);
 
-               if (!buffer) {
-                       DRM_DEBUG_KMS("buffer is null\n");
+               if (!obj) {
+                       DRM_DEBUG_KMS("gem object is null\n");
                        return -EFAULT;
                }
 
-               exynos_plane->dma_addr[i] = buffer->dma_addr +
+               exynos_plane->dma_addr[i] = obj->dma_addr +
                                            state->fb->offsets[i];
 
                DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
@@ -179,8 +168,8 @@ static void exynos_plane_atomic_update(struct drm_plane *plane,
                              state->src_x >> 16, state->src_y >> 16,
                              state->src_w >> 16, state->src_h >> 16);
 
-       if (exynos_crtc->ops->win_commit)
-               exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos);
+       if (exynos_crtc->ops->update_plane)
+               exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane);
 }
 
 static void exynos_plane_atomic_disable(struct drm_plane *plane,
@@ -192,9 +181,9 @@ static void exynos_plane_atomic_disable(struct drm_plane *plane,
        if (!old_state->crtc)
                return;
 
-       if (exynos_crtc->ops->win_disable)
-               exynos_crtc->ops->win_disable(exynos_crtc,
-                                             exynos_plane->zpos);
+       if (exynos_crtc->ops->disable_plane)
+               exynos_crtc->ops->disable_plane(exynos_crtc,
+                                               exynos_plane);
 }
 
 static const struct drm_plane_helper_funcs plane_helper_funcs = {
index 3413393d8a165ba5041222d8c6635b9d33d55969..581af35861a6fcd5781cf207d5c1a821c0583d0d 100644 (file)
@@ -25,7 +25,6 @@
 #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"
 
 /* vidi has totally three virtual windows. */
                                        connector)
 
 struct vidi_context {
-       struct exynos_drm_display       display;
+       struct drm_encoder              encoder;
        struct platform_device          *pdev;
        struct drm_device               *drm_dev;
        struct exynos_drm_crtc          *crtc;
-       struct drm_encoder              *encoder;
        struct drm_connector            connector;
        struct exynos_drm_plane         planes[WINDOWS_NR];
        struct edid                     *raw_edid;
@@ -55,9 +53,9 @@ struct vidi_context {
        int                             pipe;
 };
 
-static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
+static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e)
 {
-       return container_of(d, struct vidi_context, display);
+       return container_of(e, struct vidi_context, encoder);
 }
 
 static const char fake_edid_info[] = {
@@ -100,7 +98,7 @@ static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
        /*
         * in case of page flip request, vidi_finish_pageflip function
         * will not be called because direct_vblank is true and then
-        * that function will be called by crtc_ops->win_commit callback
+        * that function will be called by crtc_ops->update_plane callback
         */
        schedule_work(&ctx->work);
 
@@ -118,19 +116,14 @@ static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
                ctx->vblank_on = false;
 }
 
-static void vidi_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
+static void vidi_update_plane(struct exynos_drm_crtc *crtc,
+                             struct exynos_drm_plane *plane)
 {
        struct vidi_context *ctx = crtc->ctx;
-       struct exynos_drm_plane *plane;
 
        if (ctx->suspended)
                return;
 
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-       plane = &ctx->planes[win];
-
        DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr);
 
        if (ctx->vblank_on)
@@ -179,7 +172,7 @@ static const struct exynos_drm_crtc_ops vidi_crtc_ops = {
        .disable = vidi_disable,
        .enable_vblank = vidi_enable_vblank,
        .disable_vblank = vidi_disable_vblank,
-       .win_commit = vidi_win_commit,
+       .update_plane = vidi_update_plane,
 };
 
 static void vidi_fake_vblank_handler(struct work_struct *work)
@@ -196,7 +189,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
        mutex_lock(&ctx->lock);
 
        if (ctx->direct_vblank) {
-               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+               drm_crtc_handle_vblank(&ctx->crtc->base);
                ctx->direct_vblank = false;
                mutex_unlock(&ctx->lock);
                return;
@@ -204,7 +197,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
 
        mutex_unlock(&ctx->lock);
 
-       exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+       exynos_drm_crtc_finish_pageflip(ctx->crtc);
 }
 
 static int vidi_show_connection(struct device *dev,
@@ -259,9 +252,7 @@ static DEVICE_ATTR(connection, 0644, vidi_show_connection,
 int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
                                struct drm_file *file_priv)
 {
-       struct vidi_context *ctx = NULL;
-       struct drm_encoder *encoder;
-       struct exynos_drm_display *display;
+       struct vidi_context *ctx = dev_get_drvdata(drm_dev->dev);
        struct drm_exynos_vidi_connection *vidi = data;
 
        if (!vidi) {
@@ -274,21 +265,6 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
                return -EINVAL;
        }
 
-       list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
-                                                               head) {
-               display = exynos_drm_get_display(encoder);
-
-               if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
-                       ctx = display_to_vidi(display);
-                       break;
-               }
-       }
-
-       if (!ctx) {
-               DRM_DEBUG_KMS("not found virtual device type encoder.\n");
-               return -EINVAL;
-       }
-
        if (ctx->connected == vidi->connection) {
                DRM_DEBUG_KMS("same connection request.\n");
                return -EINVAL;
@@ -381,7 +357,7 @@ static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
 {
        struct vidi_context *ctx = ctx_from_connector(connector);
 
-       return ctx->encoder;
+       return &ctx->encoder;
 }
 
 static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
@@ -389,14 +365,12 @@ static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
        .best_encoder = vidi_best_encoder,
 };
 
-static int vidi_create_connector(struct exynos_drm_display *display,
-                               struct drm_encoder *encoder)
+static int vidi_create_connector(struct drm_encoder *encoder)
 {
-       struct vidi_context *ctx = display_to_vidi(display);
+       struct vidi_context *ctx = encoder_to_vidi(encoder);
        struct drm_connector *connector = &ctx->connector;
        int ret;
 
-       ctx->encoder = encoder;
        connector->polled = DRM_CONNECTOR_POLL_HPD;
 
        ret = drm_connector_init(ctx->drm_dev, connector,
@@ -413,19 +387,47 @@ static int vidi_create_connector(struct exynos_drm_display *display,
        return 0;
 }
 
+static bool exynos_vidi_mode_fixup(struct drm_encoder *encoder,
+                                const struct drm_display_mode *mode,
+                                struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void exynos_vidi_mode_set(struct drm_encoder *encoder,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode)
+{
+}
 
-static struct exynos_drm_display_ops vidi_display_ops = {
-       .create_connector = vidi_create_connector,
+static void exynos_vidi_enable(struct drm_encoder *encoder)
+{
+}
+
+static void exynos_vidi_disable(struct drm_encoder *encoder)
+{
+}
+
+static struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = {
+       .mode_fixup = exynos_vidi_mode_fixup,
+       .mode_set = exynos_vidi_mode_set,
+       .enable = exynos_vidi_enable,
+       .disable = exynos_vidi_disable,
+};
+
+static struct drm_encoder_funcs exynos_vidi_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
 };
 
 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 drm_encoder *encoder = &ctx->encoder;
        struct exynos_drm_plane *exynos_plane;
        enum drm_plane_type type;
        unsigned int zpos;
-       int ret;
+       int pipe, ret;
 
        vidi_ctx_initialize(ctx, drm_dev);
 
@@ -447,9 +449,24 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
                return PTR_ERR(ctx->crtc);
        }
 
-       ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
+       pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
+                                                 EXYNOS_DISPLAY_TYPE_VIDI);
+       if (pipe < 0)
+               return pipe;
+
+       encoder->possible_crtcs = 1 << pipe;
+
+       DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+       drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+
+       drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs);
+
+       ret = vidi_create_connector(encoder);
        if (ret) {
-               ctx->crtc->base.funcs->destroy(&ctx->crtc->base);
+               DRM_ERROR("failed to create connector ret = %d\n", ret);
+               drm_encoder_cleanup(encoder);
                return ret;
        }
 
@@ -475,8 +492,6 @@ static int vidi_probe(struct platform_device *pdev)
        if (!ctx)
                return -ENOMEM;
 
-       ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
-       ctx->display.ops = &vidi_display_ops;
        ctx->default_win = 0;
        ctx->pdev = pdev;
 
index 99e286489031c4a2931565823e0158428548aef2..932f7fa240f83cface947f21fb30dd3684f8d7c8 100644 (file)
@@ -22,7 +22,6 @@
 #include "regs-hdmi.h"
 
 #include <linux/kernel.h>
-#include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
@@ -33,8 +32,8 @@
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
 #include <linux/io.h>
-#include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/hdmi.h>
 #include <linux/component.h>
@@ -48,7 +47,6 @@
 #include "exynos_mixer.h"
 
 #include <linux/gpio.h>
-#include <media/s5p_hdmi.h>
 
 #define ctx_from_connector(c)  container_of(c, struct hdmi_context, connector)
 
@@ -88,109 +86,14 @@ struct hdmi_resources {
        int                             regul_count;
 };
 
-struct hdmi_tg_regs {
-       u8 cmd[1];
-       u8 h_fsz[2];
-       u8 hact_st[2];
-       u8 hact_sz[2];
-       u8 v_fsz[2];
-       u8 vsync[2];
-       u8 vsync2[2];
-       u8 vact_st[2];
-       u8 vact_sz[2];
-       u8 field_chg[2];
-       u8 vact_st2[2];
-       u8 vact_st3[2];
-       u8 vact_st4[2];
-       u8 vsync_top_hdmi[2];
-       u8 vsync_bot_hdmi[2];
-       u8 field_top_hdmi[2];
-       u8 field_bot_hdmi[2];
-       u8 tg_3d[1];
-};
-
-struct hdmi_v13_core_regs {
-       u8 h_blank[2];
-       u8 v_blank[3];
-       u8 h_v_line[3];
-       u8 vsync_pol[1];
-       u8 int_pro_mode[1];
-       u8 v_blank_f[3];
-       u8 h_sync_gen[3];
-       u8 v_sync_gen1[3];
-       u8 v_sync_gen2[3];
-       u8 v_sync_gen3[3];
-};
-
-struct hdmi_v14_core_regs {
-       u8 h_blank[2];
-       u8 v2_blank[2];
-       u8 v1_blank[2];
-       u8 v_line[2];
-       u8 h_line[2];
-       u8 hsync_pol[1];
-       u8 vsync_pol[1];
-       u8 int_pro_mode[1];
-       u8 v_blank_f0[2];
-       u8 v_blank_f1[2];
-       u8 h_sync_start[2];
-       u8 h_sync_end[2];
-       u8 v_sync_line_bef_2[2];
-       u8 v_sync_line_bef_1[2];
-       u8 v_sync_line_aft_2[2];
-       u8 v_sync_line_aft_1[2];
-       u8 v_sync_line_aft_pxl_2[2];
-       u8 v_sync_line_aft_pxl_1[2];
-       u8 v_blank_f2[2]; /* for 3D mode */
-       u8 v_blank_f3[2]; /* for 3D mode */
-       u8 v_blank_f4[2]; /* for 3D mode */
-       u8 v_blank_f5[2]; /* for 3D mode */
-       u8 v_sync_line_aft_3[2];
-       u8 v_sync_line_aft_4[2];
-       u8 v_sync_line_aft_5[2];
-       u8 v_sync_line_aft_6[2];
-       u8 v_sync_line_aft_pxl_3[2];
-       u8 v_sync_line_aft_pxl_4[2];
-       u8 v_sync_line_aft_pxl_5[2];
-       u8 v_sync_line_aft_pxl_6[2];
-       u8 vact_space_1[2];
-       u8 vact_space_2[2];
-       u8 vact_space_3[2];
-       u8 vact_space_4[2];
-       u8 vact_space_5[2];
-       u8 vact_space_6[2];
-};
-
-struct hdmi_v13_conf {
-       struct hdmi_v13_core_regs core;
-       struct hdmi_tg_regs tg;
-};
-
-struct hdmi_v14_conf {
-       struct hdmi_v14_core_regs core;
-       struct hdmi_tg_regs tg;
-};
-
-struct hdmi_conf_regs {
-       int pixel_clock;
-       int cea_video_id;
-       enum hdmi_picture_aspect aspect_ratio;
-       union {
-               struct hdmi_v13_conf v13_conf;
-               struct hdmi_v14_conf v14_conf;
-       } conf;
-};
-
 struct hdmi_context {
-       struct exynos_drm_display       display;
+       struct drm_encoder              encoder;
        struct device                   *dev;
        struct drm_device               *drm_dev;
        struct drm_connector            connector;
-       struct drm_encoder              *encoder;
        bool                            hpd;
        bool                            powered;
        bool                            dvi_mode;
-       struct mutex                    hdmi_mutex;
 
        void __iomem                    *regs;
        int                             irq;
@@ -201,22 +104,20 @@ struct hdmi_context {
 
        /* current hdmiphy conf regs */
        struct drm_display_mode         current_mode;
-       struct hdmi_conf_regs           mode_conf;
+       u8                              cea_video_id;
 
        struct hdmi_resources           res;
+       const struct hdmi_driver_data   *drv_data;
 
        int                             hpd_gpio;
        void __iomem                    *regs_hdmiphy;
-       const struct hdmiphy_config             *phy_confs;
-       unsigned int                    phy_conf_count;
 
        struct regmap                   *pmureg;
-       enum hdmi_type                  type;
 };
 
-static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
+static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
 {
-       return container_of(d, struct hdmi_context, display);
+       return container_of(e, struct hdmi_context, encoder);
 }
 
 struct hdmiphy_config {
@@ -624,6 +525,16 @@ static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
        writeb(value, hdata->regs + reg_id);
 }
 
+static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
+                                  int bytes, u32 val)
+{
+       while (--bytes >= 0) {
+               writeb(val & 0xff, hdata->regs + reg_id);
+               val >>= 8;
+               reg_id += 4;
+       }
+}
+
 static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
                                 u32 reg_id, u32 value, u32 mask)
 {
@@ -930,7 +841,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
 
 static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
 {
-       if (hdata->type == HDMI_TYPE13)
+       if (hdata->drv_data->type == HDMI_TYPE13)
                hdmi_v13_regs_dump(hdata, prefix);
        else
                hdmi_v14_regs_dump(hdata, prefix);
@@ -957,7 +868,7 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
        u32 hdr_sum;
        u8 chksum;
        u32 mod;
-       u32 vic;
+       u8 ar;
 
        mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
        if (hdata->dvi_mode) {
@@ -988,27 +899,22 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
                 * Set the aspect ratio as per the mode, mentioned in
                 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
                 */
-               switch (hdata->mode_conf.aspect_ratio) {
+               ar = hdata->current_mode.picture_aspect_ratio;
+               switch (ar) {
                case HDMI_PICTURE_ASPECT_4_3:
-                       hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
-                                       hdata->mode_conf.aspect_ratio |
-                                       AVI_4_3_CENTER_RATIO);
+                       ar |= AVI_4_3_CENTER_RATIO;
                        break;
                case HDMI_PICTURE_ASPECT_16_9:
-                       hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
-                                       hdata->mode_conf.aspect_ratio |
-                                       AVI_16_9_CENTER_RATIO);
+                       ar |= AVI_16_9_CENTER_RATIO;
                        break;
                case HDMI_PICTURE_ASPECT_NONE:
                default:
-                       hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
-                                       hdata->mode_conf.aspect_ratio |
-                                       AVI_SAME_AS_PIC_ASPECT_RATIO);
+                       ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
                        break;
                }
+               hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
 
-               vic = hdata->mode_conf.cea_video_id;
-               hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
+               hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
 
                chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
                                        infoframe->any.length, hdr_sum);
@@ -1038,10 +944,10 @@ static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
 {
        struct hdmi_context *hdata = ctx_from_connector(connector);
 
-       hdata->hpd = gpio_get_value(hdata->hpd_gpio);
+       if (gpio_get_value(hdata->hpd_gpio))
+               return connector_status_connected;
 
-       return hdata->hpd ? connector_status_connected :
-                       connector_status_disconnected;
+       return connector_status_disconnected;
 }
 
 static void hdmi_connector_destroy(struct drm_connector *connector)
@@ -1064,6 +970,7 @@ static int hdmi_get_modes(struct drm_connector *connector)
 {
        struct hdmi_context *hdata = ctx_from_connector(connector);
        struct edid *edid;
+       int ret;
 
        if (!hdata->ddc_adpt)
                return -ENODEV;
@@ -1079,15 +986,19 @@ static int hdmi_get_modes(struct drm_connector *connector)
 
        drm_mode_connector_update_edid_property(connector, edid);
 
-       return drm_add_edid_modes(connector, edid);
+       ret = drm_add_edid_modes(connector, edid);
+
+       kfree(edid);
+
+       return ret;
 }
 
 static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
 {
        int i;
 
-       for (i = 0; i < hdata->phy_conf_count; i++)
-               if (hdata->phy_confs[i].pixel_clock == pixel_clock)
+       for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
+               if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
                        return i;
 
        DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
@@ -1120,7 +1031,7 @@ static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
 {
        struct hdmi_context *hdata = ctx_from_connector(connector);
 
-       return hdata->encoder;
+       return &hdata->encoder;
 }
 
 static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
@@ -1129,14 +1040,12 @@ static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
        .best_encoder = hdmi_best_encoder,
 };
 
-static int hdmi_create_connector(struct exynos_drm_display *display,
-                       struct drm_encoder *encoder)
+static int hdmi_create_connector(struct drm_encoder *encoder)
 {
-       struct hdmi_context *hdata = display_to_hdmi(display);
+       struct hdmi_context *hdata = encoder_to_hdmi(encoder);
        struct drm_connector *connector = &hdata->connector;
        int ret;
 
-       hdata->encoder = encoder;
        connector->interlace_allowed = true;
        connector->polled = DRM_CONNECTOR_POLL_HPD;
 
@@ -1154,23 +1063,30 @@ static int hdmi_create_connector(struct exynos_drm_display *display,
        return 0;
 }
 
-static void hdmi_mode_fixup(struct exynos_drm_display *display,
-                               struct drm_connector *connector,
-                               const struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode)
+static bool hdmi_mode_fixup(struct drm_encoder *encoder,
+                           const struct drm_display_mode *mode,
+                           struct drm_display_mode *adjusted_mode)
 {
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector;
        struct drm_display_mode *m;
        int mode_ok;
 
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
        drm_mode_set_crtcinfo(adjusted_mode, 0);
 
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->encoder == encoder)
+                       break;
+       }
+
+       if (connector->encoder != encoder)
+               return true;
+
        mode_ok = hdmi_mode_valid(connector, adjusted_mode);
 
        /* just return if user desired mode exists. */
        if (mode_ok == MODE_OK)
-               return;
+               return true;
 
        /*
         * otherwise, find the most suitable mode among modes and change it
@@ -1190,6 +1106,8 @@ static void hdmi_mode_fixup(struct exynos_drm_display *display,
                        break;
                }
        }
+
+       return true;
 }
 
 static void hdmi_set_acr(u32 freq, u8 *acr)
@@ -1252,7 +1170,7 @@ static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
        hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
        hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
 
-       if (hdata->type == HDMI_TYPE13)
+       if (hdata->drv_data->type == HDMI_TYPE13)
                hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
        else
                hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
@@ -1386,7 +1304,7 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
                                HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
        }
 
-       if (hdata->type == HDMI_TYPE13) {
+       if (hdata->drv_data->type == HDMI_TYPE13) {
                /* choose bluescreen (fecal) color */
                hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
                hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
@@ -1419,66 +1337,94 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
 
 static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
 {
-       const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
-       const struct hdmi_v13_core_regs *core =
-               &hdata->mode_conf.conf.v13_conf.core;
+       struct drm_display_mode *m = &hdata->current_mode;
+       unsigned int val;
        int tries;
 
-       /* setting core registers */
-       hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
-       hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
-       hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
-       hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+       hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
+                       (m->htotal << 12) | m->vtotal);
+
+       val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
+       hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
+
+       val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
+       hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
+
+       val = (m->hsync_start - m->hdisplay - 2);
+       val |= ((m->hsync_end - m->hdisplay - 2) << 10);
+       val |= ((m->flags & DRM_MODE_FLAG_NHSYNC)  ? 1 : 0)<<20;
+       hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
+
+       /*
+        * Quirk requirement for exynos HDMI IP design,
+        * 2 pixels less than the actual calculation for hsync_start
+        * and end.
+        */
+
+       /* Following values & calculations differ for different type of modes */
+       if (m->flags & DRM_MODE_FLAG_INTERLACE) {
+               /* Interlaced Mode */
+               val = ((m->vsync_end - m->vdisplay) / 2);
+               val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
+
+               val = m->vtotal / 2;
+               val |= ((m->vtotal - m->vdisplay) / 2) << 11;
+               hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
+
+               val = (m->vtotal +
+                       ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
+               val |= m->vtotal << 11;
+               hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
+
+               val = ((m->vtotal / 2) + 7);
+               val |= ((m->vtotal / 2) + 2) << 12;
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
+
+               val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
+               val |= ((m->htotal / 2) +
+                       (m->hsync_start - m->hdisplay)) << 12;
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
+
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
+                               (m->vtotal - m->vdisplay) / 2);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
+
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
+       } else {
+               /* Progressive Mode */
+
+               val = m->vtotal;
+               val |= (m->vtotal - m->vdisplay) << 11;
+               hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
+
+               hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
+
+               val = (m->vsync_end - m->vdisplay);
+               val |= ((m->vsync_start - m->vdisplay) << 12);
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
+
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
+                               m->vtotal - m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
+       }
+
        /* Timing generator registers */
-       hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
+       hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
+       hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
+       hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
+       hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
 
        /* waiting for HDMIPHY's PLL to get to steady state */
        for (tries = 100; tries; --tries) {
@@ -1503,144 +1449,119 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
 
 static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
 {
-       const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
-       const struct hdmi_v14_core_regs *core =
-               &hdata->mode_conf.conf.v14_conf.core;
+       struct drm_display_mode *m = &hdata->current_mode;
        int tries;
 
-       /* setting core registers */
-       hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
-       hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
-       hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
-       hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
-       hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
-       hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
-       hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
-       hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
-       hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
-       hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
-       hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
-       hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
-       hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
-       hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
-       hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
-                       core->v_sync_line_bef_2[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
-                       core->v_sync_line_bef_2[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
-                       core->v_sync_line_bef_1[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
-                       core->v_sync_line_bef_1[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
-                       core->v_sync_line_aft_2[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
-                       core->v_sync_line_aft_2[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
-                       core->v_sync_line_aft_1[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
-                       core->v_sync_line_aft_1[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
-                       core->v_sync_line_aft_pxl_2[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
-                       core->v_sync_line_aft_pxl_2[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
-                       core->v_sync_line_aft_pxl_1[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
-                       core->v_sync_line_aft_pxl_1[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
-                       core->v_sync_line_aft_3[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
-                       core->v_sync_line_aft_3[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
-                       core->v_sync_line_aft_4[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
-                       core->v_sync_line_aft_4[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
-                       core->v_sync_line_aft_5[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
-                       core->v_sync_line_aft_5[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
-                       core->v_sync_line_aft_6[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
-                       core->v_sync_line_aft_6[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
-                       core->v_sync_line_aft_pxl_3[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
-                       core->v_sync_line_aft_pxl_3[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
-                       core->v_sync_line_aft_pxl_4[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
-                       core->v_sync_line_aft_pxl_4[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
-                       core->v_sync_line_aft_pxl_5[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
-                       core->v_sync_line_aft_pxl_5[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
-                       core->v_sync_line_aft_pxl_6[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
-                       core->v_sync_line_aft_pxl_6[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
+       hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
+       hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
+       hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
+                       (m->flags & DRM_MODE_FLAG_NHSYNC)  ? 1 : 0);
+       hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
+                       (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
+       hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
+                       (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
+
+       /*
+        * Quirk requirement for exynos 5 HDMI IP design,
+        * 2 pixels less than the actual calculation for hsync_start
+        * and end.
+        */
+
+       /* Following values & calculations differ for different type of modes */
+       if (m->flags & DRM_MODE_FLAG_INTERLACE) {
+               /* Interlaced Mode */
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
+                       (m->vsync_end - m->vdisplay) / 2);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
+                       (m->vsync_start - m->vdisplay) / 2);
+               hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
+               hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
+                               (m->vtotal - m->vdisplay) / 2);
+               hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
+                               m->vtotal - m->vdisplay / 2);
+               hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
+                               (m->vtotal / 2) + 7);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
+                               (m->vtotal / 2) + 2);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
+                       (m->htotal / 2) + (m->hsync_start - m->hdisplay));
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
+                       (m->htotal / 2) + (m->hsync_start - m->hdisplay));
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
+                               (m->vtotal - m->vdisplay) / 2);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
+                               m->vtotal - m->vdisplay / 2);
+               hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
+                               (m->vtotal / 2) + 1);
+               hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
+                               (m->vtotal / 2) + 1);
+               hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
+                               (m->vtotal / 2) + 1);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
+       } else {
+               /* Progressive Mode */
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
+                       m->vsync_end - m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
+                       m->vsync_start - m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
+               hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
+                               m->vtotal - m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
+                               m->vtotal - m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
+               hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
+               hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
+               hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
+       }
+
+       /* Following values & calculations are same irrespective of mode type */
+       hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
+                       m->hsync_start - m->hdisplay - 2);
+       hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
+                       m->hsync_end - m->hdisplay - 2);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
 
        /* Timing generator registers */
-       hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
+       hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
+       hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
 
        /* waiting for HDMIPHY's PLL to get to steady state */
        for (tries = 100; tries; --tries) {
@@ -1665,7 +1586,7 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
 
 static void hdmi_mode_apply(struct hdmi_context *hdata)
 {
-       if (hdata->type == HDMI_TYPE13)
+       if (hdata->drv_data->type == HDMI_TYPE13)
                hdmi_v13_mode_apply(hdata);
        else
                hdmi_v14_mode_apply(hdata);
@@ -1683,7 +1604,7 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
        hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
                                HDMI_PHY_ENABLE_MODE_SET);
 
-       if (hdata->type == HDMI_TYPE13)
+       if (hdata->drv_data->type == HDMI_TYPE13)
                reg = HDMI_V13_PHY_RSTOUT;
        else
                reg = HDMI_PHY_RSTOUT;
@@ -1697,7 +1618,7 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
 
 static void hdmiphy_poweron(struct hdmi_context *hdata)
 {
-       if (hdata->type != HDMI_TYPE14)
+       if (hdata->drv_data->type != HDMI_TYPE14)
                return;
 
        DRM_DEBUG_KMS("\n");
@@ -1717,7 +1638,7 @@ static void hdmiphy_poweron(struct hdmi_context *hdata)
 
 static void hdmiphy_poweroff(struct hdmi_context *hdata)
 {
-       if (hdata->type != HDMI_TYPE14)
+       if (hdata->drv_data->type != HDMI_TYPE14)
                return;
 
        DRM_DEBUG_KMS("\n");
@@ -1743,13 +1664,14 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
        int i;
 
        /* pixel clock */
-       i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
+       i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
        if (i < 0) {
                DRM_ERROR("failed to find hdmiphy conf\n");
                return;
        }
 
-       ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
+       ret = hdmiphy_reg_write_buf(hdata, 0,
+                       hdata->drv_data->phy_confs[i].conf, 32);
        if (ret) {
                DRM_ERROR("failed to configure hdmiphy\n");
                return;
@@ -1771,10 +1693,8 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
        hdmiphy_conf_reset(hdata);
        hdmiphy_conf_apply(hdata);
 
-       mutex_lock(&hdata->hdmi_mutex);
        hdmi_start(hdata, false);
        hdmi_conf_init(hdata);
-       mutex_unlock(&hdata->hdmi_mutex);
 
        hdmi_audio_init(hdata);
 
@@ -1785,271 +1705,32 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
        hdmi_regs_dump(hdata, "start");
 }
 
-static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
-{
-       int i;
-       BUG_ON(num_bytes > 4);
-       for (i = 0; i < num_bytes; i++)
-               reg_pair[i] = (value >> (8 * i)) & 0xff;
-}
-
-static void hdmi_v13_mode_set(struct hdmi_context *hdata,
-                       struct drm_display_mode *m)
+static void hdmi_mode_set(struct drm_encoder *encoder,
+                         struct drm_display_mode *mode,
+                         struct drm_display_mode *adjusted_mode)
 {
-       struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
-       struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
-       unsigned int val;
-
-       hdata->mode_conf.cea_video_id =
-               drm_match_cea_mode((struct drm_display_mode *)m);
-       hdata->mode_conf.pixel_clock = m->clock * 1000;
-       hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
-
-       hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
-       hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
-
-       val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
-       hdmi_set_reg(core->vsync_pol, 1, val);
-
-       val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
-       hdmi_set_reg(core->int_pro_mode, 1, val);
-
-       val = (m->hsync_start - m->hdisplay - 2);
-       val |= ((m->hsync_end - m->hdisplay - 2) << 10);
-       val |= ((m->flags & DRM_MODE_FLAG_NHSYNC)  ? 1 : 0)<<20;
-       hdmi_set_reg(core->h_sync_gen, 3, val);
-
-       /*
-        * Quirk requirement for exynos HDMI IP design,
-        * 2 pixels less than the actual calculation for hsync_start
-        * and end.
-        */
-
-       /* Following values & calculations differ for different type of modes */
-       if (m->flags & DRM_MODE_FLAG_INTERLACE) {
-               /* Interlaced Mode */
-               val = ((m->vsync_end - m->vdisplay) / 2);
-               val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
-               hdmi_set_reg(core->v_sync_gen1, 3, val);
-
-               val = m->vtotal / 2;
-               val |= ((m->vtotal - m->vdisplay) / 2) << 11;
-               hdmi_set_reg(core->v_blank, 3, val);
-
-               val = (m->vtotal +
-                       ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
-               val |= m->vtotal << 11;
-               hdmi_set_reg(core->v_blank_f, 3, val);
-
-               val = ((m->vtotal / 2) + 7);
-               val |= ((m->vtotal / 2) + 2) << 12;
-               hdmi_set_reg(core->v_sync_gen2, 3, val);
-
-               val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
-               val |= ((m->htotal / 2) +
-                       (m->hsync_start - m->hdisplay)) << 12;
-               hdmi_set_reg(core->v_sync_gen3, 3, val);
-
-               hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
-               hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
-
-               hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
-       } else {
-               /* Progressive Mode */
-
-               val = m->vtotal;
-               val |= (m->vtotal - m->vdisplay) << 11;
-               hdmi_set_reg(core->v_blank, 3, val);
-
-               hdmi_set_reg(core->v_blank_f, 3, 0);
-
-               val = (m->vsync_end - m->vdisplay);
-               val |= ((m->vsync_start - m->vdisplay) << 12);
-               hdmi_set_reg(core->v_sync_gen1, 3, val);
-
-               hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value  */
-               hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value  */
-               hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
-               hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
-               hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
-       }
-
-       /* Timing generator registers */
-       hdmi_set_reg(tg->cmd, 1, 0x0);
-       hdmi_set_reg(tg->h_fsz, 2, m->htotal);
-       hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
-       hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
-       hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
-       hdmi_set_reg(tg->vsync, 2, 0x1);
-       hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
-       hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
-       hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
-}
-
-static void hdmi_v14_mode_set(struct hdmi_context *hdata,
-                       struct drm_display_mode *m)
-{
-       struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
-       struct hdmi_v14_core_regs *core =
-               &hdata->mode_conf.conf.v14_conf.core;
-
-       hdata->mode_conf.cea_video_id =
-               drm_match_cea_mode((struct drm_display_mode *)m);
-       hdata->mode_conf.pixel_clock = m->clock * 1000;
-       hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
-
-       hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
-       hdmi_set_reg(core->v_line, 2, m->vtotal);
-       hdmi_set_reg(core->h_line, 2, m->htotal);
-       hdmi_set_reg(core->hsync_pol, 1,
-                       (m->flags & DRM_MODE_FLAG_NHSYNC)  ? 1 : 0);
-       hdmi_set_reg(core->vsync_pol, 1,
-                       (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
-       hdmi_set_reg(core->int_pro_mode, 1,
-                       (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
-
-       /*
-        * Quirk requirement for exynos 5 HDMI IP design,
-        * 2 pixels less than the actual calculation for hsync_start
-        * and end.
-        */
-
-       /* Following values & calculations differ for different type of modes */
-       if (m->flags & DRM_MODE_FLAG_INTERLACE) {
-               /* Interlaced Mode */
-               hdmi_set_reg(core->v_sync_line_bef_2, 2,
-                       (m->vsync_end - m->vdisplay) / 2);
-               hdmi_set_reg(core->v_sync_line_bef_1, 2,
-                       (m->vsync_start - m->vdisplay) / 2);
-               hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
-               hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
-               hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
-               hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
-               hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
-               hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
-               hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
-                       (m->htotal / 2) + (m->hsync_start - m->hdisplay));
-               hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
-                       (m->htotal / 2) + (m->hsync_start - m->hdisplay));
-               hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
-               hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
-               hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
-               hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
-               hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
-               hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
-               hdmi_set_reg(tg->vact_st3, 2, 0x0);
-               hdmi_set_reg(tg->vact_st4, 2, 0x0);
-       } else {
-               /* Progressive Mode */
-               hdmi_set_reg(core->v_sync_line_bef_2, 2,
-                       m->vsync_end - m->vdisplay);
-               hdmi_set_reg(core->v_sync_line_bef_1, 2,
-                       m->vsync_start - m->vdisplay);
-               hdmi_set_reg(core->v2_blank, 2, m->vtotal);
-               hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
-               hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
-               hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
-               hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
-               hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
-               hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
-               hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
-               hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
-               hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
-               hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
-               hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
-               hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
-               hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
-               hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
-               hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
-       }
-
-       /* Following values & calculations are same irrespective of mode type */
-       hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
-       hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
-       hdmi_set_reg(core->vact_space_1, 2, 0xffff);
-       hdmi_set_reg(core->vact_space_2, 2, 0xffff);
-       hdmi_set_reg(core->vact_space_3, 2, 0xffff);
-       hdmi_set_reg(core->vact_space_4, 2, 0xffff);
-       hdmi_set_reg(core->vact_space_5, 2, 0xffff);
-       hdmi_set_reg(core->vact_space_6, 2, 0xffff);
-       hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
-       hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
-       hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
-       hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
-
-       /* Timing generator registers */
-       hdmi_set_reg(tg->cmd, 1, 0x0);
-       hdmi_set_reg(tg->h_fsz, 2, m->htotal);
-       hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
-       hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
-       hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
-       hdmi_set_reg(tg->vsync, 2, 0x1);
-       hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
-       hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
-       hdmi_set_reg(tg->tg_3d, 1, 0x0);
-}
-
-static void hdmi_mode_set(struct exynos_drm_display *display,
-                       struct drm_display_mode *mode)
-{
-       struct hdmi_context *hdata = display_to_hdmi(display);
-       struct drm_display_mode *m = mode;
+       struct hdmi_context *hdata = encoder_to_hdmi(encoder);
+       struct drm_display_mode *m = adjusted_mode;
 
        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" : "PROGRESSIVE");
 
-       /* preserve mode information for later use. */
-       drm_mode_copy(&hdata->current_mode, mode);
-
-       if (hdata->type == HDMI_TYPE13)
-               hdmi_v13_mode_set(hdata, mode);
-       else
-               hdmi_v14_mode_set(hdata, mode);
-}
-
-static void hdmi_commit(struct exynos_drm_display *display)
-{
-       struct hdmi_context *hdata = display_to_hdmi(display);
-
-       mutex_lock(&hdata->hdmi_mutex);
-       if (!hdata->powered) {
-               mutex_unlock(&hdata->hdmi_mutex);
-               return;
-       }
-       mutex_unlock(&hdata->hdmi_mutex);
-
-       hdmi_conf_apply(hdata);
+       drm_mode_copy(&hdata->current_mode, m);
+       hdata->cea_video_id = drm_match_cea_mode(mode);
 }
 
-static void hdmi_poweron(struct hdmi_context *hdata)
+static void hdmi_enable(struct drm_encoder *encoder)
 {
+       struct hdmi_context *hdata = encoder_to_hdmi(encoder);
        struct hdmi_resources *res = &hdata->res;
 
-       mutex_lock(&hdata->hdmi_mutex);
-       if (hdata->powered) {
-               mutex_unlock(&hdata->hdmi_mutex);
+       if (hdata->powered)
                return;
-       }
 
        hdata->powered = true;
 
-       mutex_unlock(&hdata->hdmi_mutex);
-
        pm_runtime_get_sync(hdata->dev);
 
        if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
@@ -2063,17 +1744,32 @@ static void hdmi_poweron(struct hdmi_context *hdata)
        clk_prepare_enable(res->sclk_hdmi);
 
        hdmiphy_poweron(hdata);
-       hdmi_commit(&hdata->display);
+       hdmi_conf_apply(hdata);
 }
 
-static void hdmi_poweroff(struct hdmi_context *hdata)
+static void hdmi_disable(struct drm_encoder *encoder)
 {
+       struct hdmi_context *hdata = encoder_to_hdmi(encoder);
        struct hdmi_resources *res = &hdata->res;
+       struct drm_crtc *crtc = encoder->crtc;
+       const struct drm_crtc_helper_funcs *funcs = NULL;
 
-       mutex_lock(&hdata->hdmi_mutex);
        if (!hdata->powered)
-               goto out;
-       mutex_unlock(&hdata->hdmi_mutex);
+               return;
+
+       /*
+        * The SFRs of VP and Mixer are updated by Vertical Sync of
+        * Timing generator which is a part of HDMI so the sequence
+        * to disable TV Subsystem should be as following,
+        *      VP -> Mixer -> HDMI
+        *
+        * Below codes will try to disable Mixer and VP(if used)
+        * prior to disabling HDMI.
+        */
+       if (crtc)
+               funcs = crtc->helper_private;
+       if (funcs && funcs->disable)
+               (*funcs->disable)(crtc);
 
        /* HDMI System Disable */
        hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
@@ -2093,57 +1789,18 @@ static void hdmi_poweroff(struct hdmi_context *hdata)
 
        pm_runtime_put_sync(hdata->dev);
 
-       mutex_lock(&hdata->hdmi_mutex);
        hdata->powered = false;
-
-out:
-       mutex_unlock(&hdata->hdmi_mutex);
 }
 
-static void hdmi_dpms(struct exynos_drm_display *display, int mode)
-{
-       struct hdmi_context *hdata = display_to_hdmi(display);
-       struct drm_encoder *encoder = hdata->encoder;
-       struct drm_crtc *crtc = encoder->crtc;
-       const struct drm_crtc_helper_funcs *funcs = NULL;
-
-       DRM_DEBUG_KMS("mode %d\n", mode);
-
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               hdmi_poweron(hdata);
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               /*
-                * The SFRs of VP and Mixer are updated by Vertical Sync of
-                * Timing generator which is a part of HDMI so the sequence
-                * to disable TV Subsystem should be as following,
-                *      VP -> Mixer -> HDMI
-                *
-                * Below codes will try to disable Mixer and VP(if used)
-                * prior to disabling HDMI.
-                */
-               if (crtc)
-                       funcs = crtc->helper_private;
-               if (funcs && funcs->disable)
-                       (*funcs->disable)(crtc);
-
-               hdmi_poweroff(hdata);
-               break;
-       default:
-               DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
-               break;
-       }
-}
-
-static struct exynos_drm_display_ops hdmi_display_ops = {
-       .create_connector = hdmi_create_connector,
+static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
        .mode_fixup     = hdmi_mode_fixup,
        .mode_set       = hdmi_mode_set,
-       .dpms           = hdmi_dpms,
-       .commit         = hdmi_commit,
+       .enable         = hdmi_enable,
+       .disable        = hdmi_disable,
+};
+
+static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
 };
 
 static void hdmi_hotplug_work_func(struct work_struct *work)
@@ -2152,10 +1809,6 @@ static void hdmi_hotplug_work_func(struct work_struct *work)
 
        hdata = container_of(work, struct hdmi_context, hotplug_work.work);
 
-       mutex_lock(&hdata->hdmi_mutex);
-       hdata->hpd = gpio_get_value(hdata->hpd_gpio);
-       mutex_unlock(&hdata->hdmi_mutex);
-
        if (hdata->drm_dev)
                drm_helper_hpd_irq_event(hdata->drm_dev);
 }
@@ -2254,30 +1907,6 @@ fail:
        return ret;
 }
 
-static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
-                                       (struct device *dev)
-{
-       struct device_node *np = dev->of_node;
-       struct s5p_hdmi_platform_data *pd;
-       u32 value;
-
-       pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
-       if (!pd)
-               goto err_data;
-
-       if (!of_find_property(np, "hpd-gpio", &value)) {
-               DRM_ERROR("no hpd gpio property found\n");
-               goto err_data;
-       }
-
-       pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
-
-       return pd;
-
-err_data:
-       return NULL;
-}
-
 static struct of_device_id hdmi_match_types[] = {
        {
                .compatible = "samsung,exynos5-hdmi",
@@ -2301,10 +1930,33 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
 {
        struct drm_device *drm_dev = data;
        struct hdmi_context *hdata = dev_get_drvdata(dev);
+       struct drm_encoder *encoder = &hdata->encoder;
+       int ret, pipe;
 
        hdata->drm_dev = drm_dev;
 
-       return exynos_drm_create_enc_conn(drm_dev, &hdata->display);
+       pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
+                                                 EXYNOS_DISPLAY_TYPE_HDMI);
+       if (pipe < 0)
+               return pipe;
+
+       encoder->possible_crtcs = 1 << pipe;
+
+       DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+       drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+
+       drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
+
+       ret = hdmi_create_connector(encoder);
+       if (ret) {
+               DRM_ERROR("failed to create connector ret = %d\n", ret);
+               drm_encoder_cleanup(encoder);
+               return ret;
+       }
+
+       return 0;
 }
 
 static void hdmi_unbind(struct device *dev, struct device *master, void *data)
@@ -2338,43 +1990,30 @@ static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
 static int hdmi_probe(struct platform_device *pdev)
 {
        struct device_node *ddc_node, *phy_node;
-       struct s5p_hdmi_platform_data *pdata;
-       struct hdmi_driver_data *drv_data;
        const struct of_device_id *match;
        struct device *dev = &pdev->dev;
        struct hdmi_context *hdata;
        struct resource *res;
        int ret;
 
-       if (!dev->of_node)
-               return -ENODEV;
-
-       pdata = drm_hdmi_dt_parse_pdata(dev);
-       if (!pdata)
-               return -EINVAL;
-
        hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
        if (!hdata)
                return -ENOMEM;
 
-       hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI;
-       hdata->display.ops = &hdmi_display_ops;
-
-       mutex_init(&hdata->hdmi_mutex);
-
-       platform_set_drvdata(pdev, hdata);
-
-       match = of_match_node(hdmi_match_types, dev->of_node);
+       match = of_match_device(hdmi_match_types, dev);
        if (!match)
                return -ENODEV;
 
-       drv_data = (struct hdmi_driver_data *)match->data;
-       hdata->type = drv_data->type;
-       hdata->phy_confs = drv_data->phy_confs;
-       hdata->phy_conf_count = drv_data->phy_conf_count;
+       hdata->drv_data = match->data;
+
+       platform_set_drvdata(pdev, hdata);
 
-       hdata->hpd_gpio = pdata->hpd_gpio;
        hdata->dev = dev;
+       hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
+       if (hdata->hpd_gpio < 0) {
+               DRM_ERROR("cannot get hpd gpio property\n");
+               return hdata->hpd_gpio;
+       }
 
        ret = hdmi_resources_init(hdata);
        if (ret) {
@@ -2426,7 +2065,7 @@ out_get_ddc_adpt:
        }
 
 out_get_phy_port:
-       if (drv_data->is_apb_phy) {
+       if (hdata->drv_data->is_apb_phy) {
                hdata->regs_hdmiphy = of_iomap(phy_node, 0);
                if (!hdata->regs_hdmiphy) {
                        DRM_ERROR("failed to ioremap hdmi phy\n");
@@ -2449,8 +2088,6 @@ out_get_phy_port:
                goto err_hdmiphy;
        }
 
-       hdata->hpd = gpio_get_value(hdata->hpd_gpio);
-
        INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
 
        ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
index cae98db3306205e2628b2090b731cf6cfdf79d4f..e68340c77676f3f0a8f56f07467b7558d37f56f5 100644 (file)
@@ -69,6 +69,11 @@ enum mixer_version_id {
        MXR_VER_128_0_0_184,
 };
 
+enum mixer_flag_bits {
+       MXR_BIT_POWERED,
+       MXR_BIT_VSYNC,
+};
+
 struct mixer_context {
        struct platform_device *pdev;
        struct device           *dev;
@@ -76,13 +81,11 @@ struct mixer_context {
        struct exynos_drm_crtc  *crtc;
        struct exynos_drm_plane planes[MIXER_WIN_NR];
        int                     pipe;
+       unsigned long           flags;
        bool                    interlace;
-       bool                    powered;
        bool                    vp_enabled;
        bool                    has_sclk;
-       u32                     int_en;
 
-       struct mutex            mixer_mutex;
        struct mixer_resources  mixer_res;
        enum mixer_version_id   mxr_ver;
        wait_queue_head_t       wait_vsync_queue;
@@ -380,19 +383,20 @@ static void mixer_stop(struct mixer_context *ctx)
                usleep_range(10000, 12000);
 }
 
-static void vp_video_buffer(struct mixer_context *ctx, unsigned int win)
+static void vp_video_buffer(struct mixer_context *ctx,
+                           struct exynos_drm_plane *plane)
 {
        struct mixer_resources *res = &ctx->mixer_res;
+       struct drm_plane_state *state = plane->base.state;
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_display_mode *mode = &state->crtc->mode;
        unsigned long flags;
-       struct exynos_drm_plane *plane;
        dma_addr_t luma_addr[2], chroma_addr[2];
        bool tiled_mode = false;
        bool crcb_mode = false;
        u32 val;
 
-       plane = &ctx->planes[win];
-
-       switch (plane->pixel_format) {
+       switch (fb->pixel_format) {
        case DRM_FORMAT_NV12:
                crcb_mode = false;
                break;
@@ -401,21 +405,21 @@ static void vp_video_buffer(struct mixer_context *ctx, unsigned int win)
                break;
        default:
                DRM_ERROR("pixel format for vp is wrong [%d].\n",
-                               plane->pixel_format);
+                               fb->pixel_format);
                return;
        }
 
        luma_addr[0] = plane->dma_addr[0];
        chroma_addr[0] = plane->dma_addr[1];
 
-       if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
+       if (mode->flags & 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] + plane->pitch;
-                       chroma_addr[1] = chroma_addr[0] + plane->pitch;
+                       luma_addr[1] = luma_addr[0] + fb->pitches[0];
+                       chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
                }
        } else {
                ctx->interlace = false;
@@ -436,25 +440,25 @@ static void vp_video_buffer(struct mixer_context *ctx, unsigned 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(plane->pitch) |
-               VP_IMG_VSIZE(plane->fb_height));
+       vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
+               VP_IMG_VSIZE(fb->height));
        /* chroma height has to reduced by 2 to avoid chroma distorions */
-       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_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
+               VP_IMG_VSIZE(fb->height / 2));
 
-       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_WIDTH, plane->src_w);
+       vp_reg_write(res, VP_SRC_HEIGHT, plane->src_h);
        vp_reg_write(res, VP_SRC_H_POSITION,
                        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, plane->crtc_width);
+       vp_reg_write(res, VP_DST_WIDTH, plane->crtc_w);
        vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
        if (ctx->interlace) {
-               vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
+               vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_h / 2);
                vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
        } else {
-               vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
+               vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_h);
                vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
        }
 
@@ -469,9 +473,9 @@ static void vp_video_buffer(struct mixer_context *ctx, unsigned 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, plane->mode_height);
-       mixer_cfg_rgb_fmt(ctx, plane->mode_height);
-       mixer_cfg_layer(ctx, win, true);
+       mixer_cfg_scan(ctx, mode->vdisplay);
+       mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
+       mixer_cfg_layer(ctx, plane->zpos, true);
        mixer_run(ctx);
 
        mixer_vsync_set_update(ctx, true);
@@ -491,15 +495,15 @@ static void mixer_layer_update(struct mixer_context *ctx)
 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)
+       if (plane->crtc_w != plane->src_w) {
+               if (plane->crtc_w == 2 * plane->src_w)
                        *x_ratio = 1;
                else
                        goto fail;
        }
 
-       if (plane->crtc_height != plane->src_height) {
-               if (plane->crtc_height == 2 * plane->src_height)
+       if (plane->crtc_h != plane->src_h) {
+               if (plane->crtc_h == 2 * plane->src_h)
                        *y_ratio = 1;
                else
                        goto fail;
@@ -512,20 +516,22 @@ fail:
        return -ENOTSUPP;
 }
 
-static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win)
+static void mixer_graph_buffer(struct mixer_context *ctx,
+                              struct exynos_drm_plane *plane)
 {
        struct mixer_resources *res = &ctx->mixer_res;
+       struct drm_plane_state *state = plane->base.state;
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_display_mode *mode = &state->crtc->mode;
        unsigned long flags;
-       struct exynos_drm_plane *plane;
+       unsigned int win = plane->zpos;
        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;
 
-       plane = &ctx->planes[win];
-
-       switch (plane->pixel_format) {
+       switch (fb->pixel_format) {
        case DRM_FORMAT_XRGB4444:
                fmt = MXR_FORMAT_ARGB4444;
                break;
@@ -557,12 +563,12 @@ static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win)
 
        /* converting dma address base and source offset */
        dma_addr = plane->dma_addr[0]
-               + (plane->src_x * plane->bpp >> 3)
-               + (plane->src_y * plane->pitch);
+               + (plane->src_x * fb->bits_per_pixel >> 3)
+               + (plane->src_y * fb->pitches[0]);
        src_x_offset = 0;
        src_y_offset = 0;
 
-       if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                ctx->interlace = true;
        else
                ctx->interlace = false;
@@ -576,18 +582,18 @@ static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win)
 
        /* setup geometry */
        mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
-                       plane->pitch / (plane->bpp >> 3));
+                       fb->pitches[0] / (fb->bits_per_pixel >> 3));
 
        /* setup display size */
        if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
                win == MIXER_DEFAULT_WIN) {
-               val  = MXR_MXR_RES_HEIGHT(plane->mode_height);
-               val |= MXR_MXR_RES_WIDTH(plane->mode_width);
+               val  = MXR_MXR_RES_HEIGHT(mode->vdisplay);
+               val |= MXR_MXR_RES_WIDTH(mode->hdisplay);
                mixer_reg_write(res, MXR_RESOLUTION, val);
        }
 
-       val  = MXR_GRP_WH_WIDTH(plane->src_width);
-       val |= MXR_GRP_WH_HEIGHT(plane->src_height);
+       val  = MXR_GRP_WH_WIDTH(plane->src_w);
+       val |= MXR_GRP_WH_HEIGHT(plane->src_h);
        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 +611,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win)
        /* set buffer address to mixer */
        mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
 
-       mixer_cfg_scan(ctx, plane->mode_height);
-       mixer_cfg_rgb_fmt(ctx, plane->mode_height);
+       mixer_cfg_scan(ctx, mode->vdisplay);
+       mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
        mixer_cfg_layer(ctx, win, true);
 
        /* layer update mandatory for mixer 16.0.33.0 */
@@ -718,6 +724,10 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
 
        /* handling VSYNC */
        if (val & MXR_INT_STATUS_VSYNC) {
+               /* vsync interrupt use different bit for read and clear */
+               val |= MXR_INT_CLEAR_VSYNC;
+               val &= ~MXR_INT_STATUS_VSYNC;
+
                /* interlace scan need to check shadow register */
                if (ctx->interlace) {
                        base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
@@ -731,8 +741,8 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
                                goto out;
                }
 
-               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
-               exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+               drm_crtc_handle_vblank(&ctx->crtc->base);
+               exynos_drm_crtc_finish_pageflip(ctx->crtc);
 
                /* set wait vsync event to zero and wake up queue. */
                if (atomic_read(&ctx->wait_vsync_event)) {
@@ -743,11 +753,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
 
 out:
        /* clear interrupts */
-       if (~val & MXR_INT_EN_VSYNC) {
-               /* vsync interrupt use different bit for read and clear */
-               val &= ~MXR_INT_EN_VSYNC;
-               val |= MXR_INT_CLEAR_VSYNC;
-       }
        mixer_reg_write(res, MXR_INT_STATUS, val);
 
        spin_unlock(&res->reg_slock);
@@ -882,8 +887,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
                }
        }
 
-       ret = drm_iommu_attach_device_if_possible(mixer_ctx->crtc, drm_dev,
-                                                               mixer_ctx->dev);
+       ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
        if (ret)
                priv->pipe--;
 
@@ -892,8 +896,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
 
 static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
 {
-       if (is_drm_iommu_supported(mixer_ctx->drm_dev))
-               drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
+       drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
 }
 
 static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
@@ -901,14 +904,13 @@ static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
        struct mixer_context *mixer_ctx = crtc->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
 
-       if (!mixer_ctx->powered) {
-               mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
+       __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
+       if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
                return 0;
-       }
 
        /* enable vsync interrupt */
-       mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
-                       MXR_INT_EN_VSYNC);
+       mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
+       mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
 
        return 0;
 }
@@ -918,48 +920,48 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
        struct mixer_context *mixer_ctx = crtc->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
 
+       __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
+
+       if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
+               return;
+
        /* disable vsync interrupt */
+       mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
        mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
-static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
+static void mixer_update_plane(struct exynos_drm_crtc *crtc,
+                              struct exynos_drm_plane *plane)
 {
        struct mixer_context *mixer_ctx = crtc->ctx;
 
-       DRM_DEBUG_KMS("win: %d\n", win);
+       DRM_DEBUG_KMS("win: %d\n", plane->zpos);
 
-       mutex_lock(&mixer_ctx->mixer_mutex);
-       if (!mixer_ctx->powered) {
-               mutex_unlock(&mixer_ctx->mixer_mutex);
+       if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
                return;
-       }
-       mutex_unlock(&mixer_ctx->mixer_mutex);
 
-       if (win > 1 && mixer_ctx->vp_enabled)
-               vp_video_buffer(mixer_ctx, win);
+       if (plane->zpos > 1 && mixer_ctx->vp_enabled)
+               vp_video_buffer(mixer_ctx, plane);
        else
-               mixer_graph_buffer(mixer_ctx, win);
+               mixer_graph_buffer(mixer_ctx, plane);
 }
 
-static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
+static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
+                               struct exynos_drm_plane *plane)
 {
        struct mixer_context *mixer_ctx = crtc->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
        unsigned long flags;
 
-       DRM_DEBUG_KMS("win: %d\n", win);
+       DRM_DEBUG_KMS("win: %d\n", plane->zpos);
 
-       mutex_lock(&mixer_ctx->mixer_mutex);
-       if (!mixer_ctx->powered) {
-               mutex_unlock(&mixer_ctx->mixer_mutex);
+       if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
                return;
-       }
-       mutex_unlock(&mixer_ctx->mixer_mutex);
 
        spin_lock_irqsave(&res->reg_slock, flags);
        mixer_vsync_set_update(mixer_ctx, false);
 
-       mixer_cfg_layer(mixer_ctx, win, false);
+       mixer_cfg_layer(mixer_ctx, plane->zpos, false);
 
        mixer_vsync_set_update(mixer_ctx, true);
        spin_unlock_irqrestore(&res->reg_slock, flags);
@@ -970,12 +972,8 @@ static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
        struct mixer_context *mixer_ctx = crtc->ctx;
        int err;
 
-       mutex_lock(&mixer_ctx->mixer_mutex);
-       if (!mixer_ctx->powered) {
-               mutex_unlock(&mixer_ctx->mixer_mutex);
+       if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
                return;
-       }
-       mutex_unlock(&mixer_ctx->mixer_mutex);
 
        err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
        if (err < 0) {
@@ -1003,13 +1001,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
        struct mixer_resources *res = &ctx->mixer_res;
        int ret;
 
-       mutex_lock(&ctx->mixer_mutex);
-       if (ctx->powered) {
-               mutex_unlock(&ctx->mixer_mutex);
+       if (test_bit(MXR_BIT_POWERED, &ctx->flags))
                return;
-       }
-
-       mutex_unlock(&ctx->mixer_mutex);
 
        pm_runtime_get_sync(ctx->dev);
 
@@ -1041,13 +1034,14 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
                }
        }
 
-       mutex_lock(&ctx->mixer_mutex);
-       ctx->powered = true;
-       mutex_unlock(&ctx->mixer_mutex);
+       set_bit(MXR_BIT_POWERED, &ctx->flags);
 
        mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
 
-       mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
+       if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
+               mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
+               mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
+       }
        mixer_win_reset(ctx);
 }
 
@@ -1057,24 +1051,16 @@ static void mixer_disable(struct exynos_drm_crtc *crtc)
        struct mixer_resources *res = &ctx->mixer_res;
        int i;
 
-       mutex_lock(&ctx->mixer_mutex);
-       if (!ctx->powered) {
-               mutex_unlock(&ctx->mixer_mutex);
+       if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
                return;
-       }
-       mutex_unlock(&ctx->mixer_mutex);
 
        mixer_stop(ctx);
        mixer_regs_dump(ctx);
 
        for (i = 0; i < MIXER_WIN_NR; i++)
-               mixer_win_disable(crtc, i);
-
-       ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
+               mixer_disable_plane(crtc, &ctx->planes[i]);
 
-       mutex_lock(&ctx->mixer_mutex);
-       ctx->powered = false;
-       mutex_unlock(&ctx->mixer_mutex);
+       clear_bit(MXR_BIT_POWERED, &ctx->flags);
 
        clk_disable_unprepare(res->hdmi);
        clk_disable_unprepare(res->mixer);
@@ -1113,8 +1099,8 @@ static const 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_commit             = mixer_win_commit,
-       .win_disable            = mixer_win_disable,
+       .update_plane           = mixer_update_plane,
+       .disable_plane          = mixer_disable_plane,
 };
 
 static struct mixer_drv_data exynos5420_mxr_drv_data = {
@@ -1236,8 +1222,6 @@ static int mixer_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       mutex_init(&ctx->mixer_mutex);
-
        if (dev->of_node) {
                const struct of_device_id *match;
 
index de6f62a6ceb7a2d85ab67ba2eb64e8f688c05320..db9f7d011832943a2d3537228b538b368b4cc5c1 100644 (file)
@@ -276,12 +276,12 @@ static void psbfb_copyarea_accel(struct fb_info *info,
                break;
        default:
                /* software fallback */
-               cfb_copyarea(info, a);
+               drm_fb_helper_cfb_copyarea(info, a);
                return;
        }
 
        if (!gma_power_begin(dev, false)) {
-               cfb_copyarea(info, a);
+               drm_fb_helper_cfb_copyarea(info, a);
                return;
        }
        psb_accel_2d_copy(dev_priv,
@@ -308,7 +308,7 @@ void psbfb_copyarea(struct fb_info *info,
        /* Avoid the 8 pixel erratum */
        if (region->width == 8 || region->height == 8 ||
                (info->flags & FBINFO_HWACCEL_DISABLED))
-               return cfb_copyarea(info, region);
+               return drm_fb_helper_cfb_copyarea(info, region);
 
        psbfb_copyarea_accel(info, region);
 }
index 2d42ce6d37577a45fc446117855244296b45760b..2eaf1b31c7bd8c76d8d69d60a0dd43343466e9ec 100644 (file)
@@ -194,9 +194,9 @@ static struct fb_ops psbfb_ops = {
        .fb_set_par = drm_fb_helper_set_par,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcolreg = psbfb_setcolreg,
-       .fb_fillrect = cfb_fillrect,
+       .fb_fillrect = drm_fb_helper_cfb_fillrect,
        .fb_copyarea = psbfb_copyarea,
-       .fb_imageblit = cfb_imageblit,
+       .fb_imageblit = drm_fb_helper_cfb_imageblit,
        .fb_mmap = psbfb_mmap,
        .fb_sync = psbfb_sync,
        .fb_ioctl = psbfb_ioctl,
@@ -208,9 +208,9 @@ static struct fb_ops psbfb_roll_ops = {
        .fb_set_par = drm_fb_helper_set_par,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcolreg = psbfb_setcolreg,
-       .fb_fillrect = cfb_fillrect,
-       .fb_copyarea = cfb_copyarea,
-       .fb_imageblit = cfb_imageblit,
+       .fb_fillrect = drm_fb_helper_cfb_fillrect,
+       .fb_copyarea = drm_fb_helper_cfb_copyarea,
+       .fb_imageblit = drm_fb_helper_cfb_imageblit,
        .fb_pan_display = psbfb_pan,
        .fb_mmap = psbfb_mmap,
        .fb_ioctl = psbfb_ioctl,
@@ -222,9 +222,9 @@ static struct fb_ops psbfb_unaccel_ops = {
        .fb_set_par = drm_fb_helper_set_par,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcolreg = psbfb_setcolreg,
-       .fb_fillrect = cfb_fillrect,
-       .fb_copyarea = cfb_copyarea,
-       .fb_imageblit = cfb_imageblit,
+       .fb_fillrect = drm_fb_helper_cfb_fillrect,
+       .fb_copyarea = drm_fb_helper_cfb_copyarea,
+       .fb_imageblit = drm_fb_helper_cfb_imageblit,
        .fb_mmap = psbfb_mmap,
        .fb_ioctl = psbfb_ioctl,
 };
@@ -343,7 +343,6 @@ static int psbfb_create(struct psb_fbdev *fbdev,
        struct drm_framebuffer *fb;
        struct psb_framebuffer *psbfb = &fbdev->pfb;
        struct drm_mode_fb_cmd2 mode_cmd;
-       struct device *device = &dev->pdev->dev;
        int size;
        int ret;
        struct gtt_range *backing;
@@ -409,9 +408,9 @@ static int psbfb_create(struct psb_fbdev *fbdev,
 
        mutex_lock(&dev->struct_mutex);
 
-       info = framebuffer_alloc(0, device);
-       if (!info) {
-               ret = -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(&fbdev->psb_fb_helper);
+       if (IS_ERR(info)) {
+               ret = PTR_ERR(info);
                goto out_err1;
        }
        info->par = fbdev;
@@ -426,7 +425,6 @@ static int psbfb_create(struct psb_fbdev *fbdev,
        psbfb->fbdev = info;
 
        fbdev->psb_fb_helper.fb = fb;
-       fbdev->psb_fb_helper.fbdev = info;
 
        drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
        strcpy(info->fix.id, "psbdrmfb");
@@ -440,12 +438,6 @@ static int psbfb_create(struct psb_fbdev *fbdev,
        } else  /* Software */
                info->fbops = &psbfb_unaccel_ops;
 
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto out_unref;
-       }
-
        info->fix.smem_start = dev->mode_config.fb_base;
        info->fix.smem_len = size;
        info->fix.ywrapstep = gtt_roll;
@@ -456,11 +448,6 @@ static int psbfb_create(struct psb_fbdev *fbdev,
        info->screen_size = size;
 
        if (dev_priv->gtt.stolen_size) {
-               info->apertures = alloc_apertures(1);
-               if (!info->apertures) {
-                       ret = -ENOMEM;
-                       goto out_unref;
-               }
                info->apertures->ranges[0].base = dev->mode_config.fb_base;
                info->apertures->ranges[0].size = dev_priv->gtt.stolen_size;
        }
@@ -483,6 +470,8 @@ out_unref:
                psb_gtt_free_range(dev, backing);
        else
                drm_gem_object_unreference(&backing->gem);
+
+       drm_fb_helper_release_fbi(&fbdev->psb_fb_helper);
 out_err1:
        mutex_unlock(&dev->struct_mutex);
        psb_gtt_free_range(dev, backing);
@@ -570,16 +559,11 @@ static const struct drm_fb_helper_funcs psb_fb_helper_funcs = {
 
 static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
 {
-       struct fb_info *info;
        struct psb_framebuffer *psbfb = &fbdev->pfb;
 
-       if (fbdev->psb_fb_helper.fbdev) {
-               info = fbdev->psb_fb_helper.fbdev;
-               unregister_framebuffer(info);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&fbdev->psb_fb_helper);
+       drm_fb_helper_release_fbi(&fbdev->psb_fb_helper);
+
        drm_fb_helper_fini(&fbdev->psb_fb_helper);
        drm_framebuffer_unregister_private(&psbfb->base);
        drm_framebuffer_cleanup(&psbfb->base);
index fe1599d75f14e39b2a39364b78d088d4715c368f..424228be79ae5b2aa1557ca07331e4e49e665ef8 100644 (file)
@@ -606,8 +606,6 @@ static void
 tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr,
                 uint8_t *buf, size_t size)
 {
-       buf[PB(0)] = tda998x_cksum(buf, size);
-
        reg_clear(priv, REG_DIP_IF_FLAGS, bit);
        reg_write_range(priv, addr, buf, size);
        reg_set(priv, REG_DIP_IF_FLAGS, bit);
@@ -627,6 +625,8 @@ tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p)
        buf[PB(4)] = p->audio_frame[4];
        buf[PB(5)] = p->audio_frame[5] & 0xf8; /* DM_INH + LSV */
 
+       buf[PB(0)] = tda998x_cksum(buf, sizeof(buf));
+
        tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf,
                         sizeof(buf));
 }
index eb87e2538861506409ad7651a6a5b7738e771fa4..051eab33e4c7b13260994ebb884cc44a5394c4bc 100644 (file)
@@ -36,21 +36,6 @@ config DRM_I915
          i810 driver instead, and the Atom z5xx series has an entirely
          different implementation.
 
-config DRM_I915_FBDEV
-       bool "Enable legacy fbdev support for the modesetting intel driver"
-       depends on DRM_I915
-       select DRM_KMS_FB_HELPER
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
-       default y
-       help
-         Choose this option if you have a need for the legacy fbdev
-         support. Note that this support also provide the linux console
-         support on top of the intel modesetting driver.
-
-         If in doubt, say "Y".
-
 config DRM_I915_PRELIMINARY_HW_SUPPORT
        bool "Enable preliminary support for prerelease Intel hardware by default"
        depends on DRM_I915
index e52e0125164450ad7f1e2dea841000b7a24c94bb..998b4643109f6cf46021b40fe88f606303c79893 100644 (file)
@@ -6,12 +6,13 @@
 
 # core driver code
 i915-y := i915_drv.o \
+         i915_irq.o \
          i915_params.o \
           i915_suspend.o \
          i915_sysfs.o \
+         intel_csr.o \
          intel_pm.o \
-         intel_runtime_pm.o \
-         intel_csr.o
+         intel_runtime_pm.o
 
 i915-$(CONFIG_COMPAT)   += i915_ioc32.o
 i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
@@ -20,21 +21,20 @@ i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
 i915-y += i915_cmd_parser.o \
          i915_gem_batch_pool.o \
          i915_gem_context.o \
-         i915_gem_render_state.o \
          i915_gem_debug.o \
          i915_gem_dmabuf.o \
          i915_gem_evict.o \
          i915_gem_execbuffer.o \
+         i915_gem_fence.o \
          i915_gem_gtt.o \
          i915_gem.o \
+         i915_gem_render_state.o \
          i915_gem_shrinker.o \
          i915_gem_stolen.o \
          i915_gem_tiling.o \
          i915_gem_userptr.o \
          i915_gpu_error.o \
-         i915_irq.o \
          i915_trace_points.o \
-         intel_hotplug.o \
          intel_lrc.o \
          intel_mocs.o \
          intel_ringbuffer.o \
@@ -48,18 +48,21 @@ i915-y += intel_renderstate_gen6.o \
 
 # modesetting core code
 i915-y += intel_audio.o \
+         intel_atomic.o \
+         intel_atomic_plane.o \
          intel_bios.o \
          intel_display.o \
          intel_fbc.o \
          intel_fifo_underrun.o \
          intel_frontbuffer.o \
+         intel_hotplug.o \
          intel_modes.o \
          intel_overlay.o \
          intel_psr.o \
          intel_sideband.o \
          intel_sprite.o
 i915-$(CONFIG_ACPI)            += intel_acpi.o intel_opregion.o
-i915-$(CONFIG_DRM_I915_FBDEV)  += intel_fbdev.o
+i915-$(CONFIG_DRM_FBDEV_EMULATION)     += intel_fbdev.o
 
 # modesetting output/encoder code
 i915-y += dvo_ch7017.o \
@@ -68,15 +71,13 @@ i915-y += dvo_ch7017.o \
          dvo_ns2501.o \
          dvo_sil164.o \
          dvo_tfp410.o \
-         intel_atomic.o \
-         intel_atomic_plane.o \
          intel_crt.o \
          intel_ddi.o \
-         intel_dp.o \
          intel_dp_mst.o \
+         intel_dp.o \
          intel_dsi.o \
-         intel_dsi_pll.o \
          intel_dsi_panel_vbt.o \
+         intel_dsi_pll.o \
          intel_dvo.o \
          intel_hdmi.o \
          intel_i2c.o \
index 430571b977db9d771a2ff15ae543526e3a321418..237ff6884a2227bc9b7520ed4bcaabe75d924f74 100644 (file)
@@ -151,8 +151,8 @@ static const struct drm_i915_cmd_descriptor render_cmds[] = {
        CMD(  MI_ARB_ON_OFF,                    SMI,    F,  1,      R  ),
        CMD(  MI_PREDICATE,                     SMI,    F,  1,      S  ),
        CMD(  MI_TOPOLOGY_FILTER,               SMI,    F,  1,      S  ),
-       CMD(  MI_DISPLAY_FLIP,                  SMI,   !F,  0xFF,   R  ),
        CMD(  MI_SET_APPID,                     SMI,    F,  1,      S  ),
+       CMD(  MI_DISPLAY_FLIP,                  SMI,   !F,  0xFF,   R  ),
        CMD(  MI_SET_CONTEXT,                   SMI,   !F,  0xFF,   R  ),
        CMD(  MI_URB_CLEAR,                     SMI,   !F,  0xFF,   S  ),
        CMD(  MI_STORE_DWORD_IMM,               SMI,   !F,  0x3F,   B,
@@ -564,7 +564,7 @@ static bool validate_cmds_sorted(struct intel_engine_cs *ring,
 
                for (j = 0; j < table->count; j++) {
                        const struct drm_i915_cmd_descriptor *desc =
-                               &table->table[i];
+                               &table->table[j];
                        u32 curr = desc->cmd.value & desc->cmd.mask;
 
                        if (curr < previous) {
index 51580bdd587fd8e6e3ef3f4820682924bdc35003..33aabc79813b70e03ae9eb2e07c54df847ef93f8 100644 (file)
@@ -1868,7 +1868,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
        struct intel_framebuffer *fb;
        struct drm_framebuffer *drm_fb;
 
-#ifdef CONFIG_DRM_I915_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        ifbdev = dev_priv->fbdev;
@@ -3645,74 +3645,40 @@ static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
        return 0;
 }
 
-static void hsw_trans_edp_pipe_A_crc_wa(struct drm_device *dev)
+static void hsw_trans_edp_pipe_A_crc_wa(struct drm_device *dev, bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *crtc =
                to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_A]);
        struct intel_crtc_state *pipe_config;
+       struct drm_atomic_state *state;
+       int ret = 0;
 
        drm_modeset_lock_all(dev);
-       pipe_config = to_intel_crtc_state(crtc->base.state);
-
-       /*
-        * If we use the eDP transcoder we need to make sure that we don't
-        * bypass the pfit, since otherwise the pipe CRC source won't work. Only
-        * relevant on hsw with pipe A when using the always-on power well
-        * routing.
-        */
-       if (pipe_config->cpu_transcoder == TRANSCODER_EDP &&
-           !pipe_config->pch_pfit.enabled) {
-               bool active = pipe_config->base.active;
-
-               if (active) {
-                       intel_crtc_control(&crtc->base, false);
-                       pipe_config = to_intel_crtc_state(crtc->base.state);
-               }
-
-               pipe_config->pch_pfit.force_thru = true;
-
-               intel_display_power_get(dev_priv,
-                                       POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A));
-
-               if (active)
-                       intel_crtc_control(&crtc->base, true);
+       state = drm_atomic_state_alloc(dev);
+       if (!state) {
+               ret = -ENOMEM;
+               goto out;
        }
-       drm_modeset_unlock_all(dev);
-}
-
-static void hsw_undo_trans_edp_pipe_A_crc_wa(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *crtc =
-               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_A]);
-       struct intel_crtc_state *pipe_config;
-
-       drm_modeset_lock_all(dev);
-       /*
-        * If we use the eDP transcoder we need to make sure that we don't
-        * bypass the pfit, since otherwise the pipe CRC source won't work. Only
-        * relevant on hsw with pipe A when using the always-on power well
-        * routing.
-        */
-       pipe_config = to_intel_crtc_state(crtc->base.state);
-       if (pipe_config->pch_pfit.force_thru) {
-               bool active = pipe_config->base.active;
-
-               if (active) {
-                       intel_crtc_control(&crtc->base, false);
-                       pipe_config = to_intel_crtc_state(crtc->base.state);
-               }
 
-               pipe_config->pch_pfit.force_thru = false;
+       state->acquire_ctx = drm_modeset_legacy_acquire_ctx(&crtc->base);
+       pipe_config = intel_atomic_get_crtc_state(state, crtc);
+       if (IS_ERR(pipe_config)) {
+               ret = PTR_ERR(pipe_config);
+               goto out;
+       }
 
-               intel_display_power_put(dev_priv,
-                                       POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A));
+       pipe_config->pch_pfit.force_thru = enable;
+       if (pipe_config->cpu_transcoder == TRANSCODER_EDP &&
+           pipe_config->pch_pfit.enabled != enable)
+               pipe_config->base.connectors_changed = true;
 
-               if (active)
-                       intel_crtc_control(&crtc->base, true);
-       }
+       ret = drm_atomic_commit(state);
+out:
        drm_modeset_unlock_all(dev);
+       WARN(ret, "Toggling workaround to %i returns %i\n", enable, ret);
+       if (ret)
+               drm_atomic_state_free(state);
 }
 
 static int ivb_pipe_crc_ctl_reg(struct drm_device *dev,
@@ -3732,7 +3698,7 @@ static int ivb_pipe_crc_ctl_reg(struct drm_device *dev,
                break;
        case INTEL_PIPE_CRC_SOURCE_PF:
                if (IS_HASWELL(dev) && pipe == PIPE_A)
-                       hsw_trans_edp_pipe_A_crc_wa(dev);
+                       hsw_trans_edp_pipe_A_crc_wa(dev, true);
 
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB;
                break;
@@ -3844,7 +3810,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
                else if (IS_VALLEYVIEW(dev))
                        vlv_undo_pipe_scramble_reset(dev, pipe);
                else if (IS_HASWELL(dev) && pipe == PIPE_A)
-                       hsw_undo_trans_edp_pipe_A_crc_wa(dev);
+                       hsw_trans_edp_pipe_A_crc_wa(dev, false);
 
                hsw_enable_ips(crtc);
        }
@@ -4030,24 +3996,14 @@ static ssize_t i915_displayport_test_active_write(struct file *file,
 {
        char *input_buffer;
        int status = 0;
-       struct seq_file *m;
        struct drm_device *dev;
        struct drm_connector *connector;
        struct list_head *connector_list;
        struct intel_dp *intel_dp;
        int val = 0;
 
-       m = file->private_data;
-       if (!m) {
-               status = -ENODEV;
-               return status;
-       }
-       dev = m->private;
+       dev = ((struct seq_file *)file->private_data)->private;
 
-       if (!dev) {
-               status = -ENODEV;
-               return status;
-       }
        connector_list = &dev->mode_config.connector_list;
 
        if (len == 0)
@@ -4071,9 +4027,7 @@ static ssize_t i915_displayport_test_active_write(struct file *file,
                    DRM_MODE_CONNECTOR_DisplayPort)
                        continue;
 
-               if (connector->connector_type ==
-                   DRM_MODE_CONNECTOR_DisplayPort &&
-                   connector->status == connector_status_connected &&
+               if (connector->status == connector_status_connected &&
                    connector->encoder != NULL) {
                        intel_dp = enc_to_intel_dp(connector->encoder);
                        status = kstrtoint(input_buffer, 10, &val);
@@ -4105,9 +4059,6 @@ static int i915_displayport_test_active_show(struct seq_file *m, void *data)
        struct list_head *connector_list = &dev->mode_config.connector_list;
        struct intel_dp *intel_dp;
 
-       if (!dev)
-               return -ENODEV;
-
        list_for_each_entry(connector, connector_list, head) {
 
                if (connector->connector_type !=
@@ -4152,9 +4103,6 @@ static int i915_displayport_test_data_show(struct seq_file *m, void *data)
        struct list_head *connector_list = &dev->mode_config.connector_list;
        struct intel_dp *intel_dp;
 
-       if (!dev)
-               return -ENODEV;
-
        list_for_each_entry(connector, connector_list, head) {
 
                if (connector->connector_type !=
@@ -4194,9 +4142,6 @@ static int i915_displayport_test_type_show(struct seq_file *m, void *data)
        struct list_head *connector_list = &dev->mode_config.connector_list;
        struct intel_dp *intel_dp;
 
-       if (!dev)
-               return -ENODEV;
-
        list_for_each_entry(connector, connector_list, head) {
 
                if (connector->connector_type !=
index b1f9e5561cf2c73d1a9ca62536663322cb370ec6..ab37d1121be8277728bff5d25a0cb4a4599de0aa 100644 (file)
@@ -1274,13 +1274,3 @@ const struct drm_ioctl_desc i915_ioctls[] = {
 };
 
 int i915_max_ioctl = ARRAY_SIZE(i915_ioctls);
-
-/*
- * This is really ugly: Because old userspace abused the linux agp interface to
- * manage the gtt, we need to claim that all intel devices are agp.  For
- * otherwise the drm core refuses to initialize the agp support code.
- */
-int i915_driver_device_is_agp(struct drm_device *dev)
-{
-       return 1;
-}
index 0d6775a3e88c3e09254874b3a99d0d950d5f0f5c..1d887459e37fd717992ddbfb52228d8550e55a09 100644 (file)
@@ -935,8 +935,6 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (PCI_FUNC(pdev->devfn))
                return -ENODEV;
 
-       driver.driver_features &= ~(DRIVER_USE_AGP);
-
        return drm_get_pci_dev(pdev, ent, &driver);
 }
 
@@ -1491,7 +1489,15 @@ static int intel_runtime_suspend(struct device *device)
         * FIXME: We really should find a document that references the arguments
         * used below!
         */
-       if (IS_HASWELL(dev)) {
+       if (IS_BROADWELL(dev)) {
+               /*
+                * On Broadwell, if we use PCI_D1 the PCH DDI ports will stop
+                * being detected, and the call we do at intel_runtime_resume()
+                * won't be able to restore them. Since PCI_D3hot matches the
+                * actual specification and appears to be working, use it.
+                */
+               intel_opregion_notify_adapter(dev, PCI_D3hot);
+       } else {
                /*
                 * current versions of firmware which depend on this opregion
                 * notification have repurposed the D1 definition to mean
@@ -1500,16 +1506,6 @@ static int intel_runtime_suspend(struct device *device)
                 * the suspend path.
                 */
                intel_opregion_notify_adapter(dev, PCI_D1);
-       } else {
-               /*
-                * On Broadwell, if we use PCI_D1 the PCH DDI ports will stop
-                * being detected, and the call we do at intel_runtime_resume()
-                * won't be able to restore them. Since PCI_D3hot matches the
-                * actual specification and appears to be working, use it. Let's
-                * assume the other non-Haswell platforms will stay the same as
-                * Broadwell.
-                */
-               intel_opregion_notify_adapter(dev, PCI_D3hot);
        }
 
        assert_forcewakes_inactive(dev_priv);
@@ -1649,7 +1645,6 @@ static struct drm_driver driver = {
         * deal with them for Intel hardware.
         */
        .driver_features =
-           DRIVER_USE_AGP |
            DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME |
            DRIVER_RENDER,
        .load = i915_driver_load,
@@ -1664,7 +1659,6 @@ static struct drm_driver driver = {
        .suspend = i915_suspend_legacy,
        .resume = i915_resume_legacy,
 
-       .device_is_agp = i915_driver_device_is_agp,
 #if defined(CONFIG_DEBUG_FS)
        .debugfs_init = i915_debugfs_init,
        .debugfs_cleanup = i915_debugfs_cleanup,
index 23ce125e0298e05b430f05daf45ef56952948fed..599441beea17e539f13a122ea398923101b1764b 100644 (file)
@@ -56,7 +56,7 @@
 
 #define DRIVER_NAME            "i915"
 #define DRIVER_DESC            "Intel Graphics"
-#define DRIVER_DATE            "20150717"
+#define DRIVER_DATE            "20150731"
 
 #undef WARN_ON
 /* Many gcc seem to no see through this and fall over :( */
@@ -206,11 +206,11 @@ enum intel_display_power_domain {
 
 enum hpd_pin {
        HPD_NONE = 0,
-       HPD_PORT_A = HPD_NONE, /* PORT_A is internal */
        HPD_TV = HPD_NONE,     /* TV is known to be unreliable */
        HPD_CRT,
        HPD_SDVO_B,
        HPD_SDVO_C,
+       HPD_PORT_A,
        HPD_PORT_B,
        HPD_PORT_C,
        HPD_PORT_D,
@@ -484,6 +484,7 @@ struct drm_i915_error_state {
        struct timeval time;
 
        char error_msg[128];
+       int iommu;
        u32 reset_count;
        u32 suspend_count;
 
@@ -742,7 +743,7 @@ enum csr_state {
 
 struct intel_csr {
        const char *fw_path;
-       __be32 *dmc_payload;
+       uint32_t *dmc_payload;
        uint32_t dmc_fw_size;
        uint32_t mmio_count;
        uint32_t mmioaddr[8];
@@ -894,6 +895,7 @@ enum fb_op_origin {
        ORIGIN_CPU,
        ORIGIN_CS,
        ORIGIN_FLIP,
+       ORIGIN_DIRTYFB,
 };
 
 struct i915_fbc {
@@ -1408,6 +1410,11 @@ enum modeset_restore {
        MODESET_SUSPENDED,
 };
 
+#define DP_AUX_A 0x40
+#define DP_AUX_B 0x10
+#define DP_AUX_C 0x20
+#define DP_AUX_D 0x30
+
 struct ddi_vbt_port_info {
        /*
         * This is an index in the HDMI/DVI DDI buffer translation table.
@@ -1420,6 +1427,11 @@ struct ddi_vbt_port_info {
        uint8_t supports_dvi:1;
        uint8_t supports_hdmi:1;
        uint8_t supports_dp:1;
+
+       uint8_t alternate_aux_channel;
+
+       uint8_t dp_boost_level;
+       uint8_t hdmi_boost_level;
 };
 
 enum psr_lines_to_wait {
@@ -1854,7 +1866,7 @@ struct drm_i915_private {
 
        struct drm_i915_gem_object *vlv_pctx;
 
-#ifdef CONFIG_DRM_I915_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
        struct work_struct fbdev_suspend_work;
@@ -2610,6 +2622,8 @@ struct i915_params {
        bool reset;
        bool disable_display;
        bool disable_vtd_wa;
+       bool enable_guc_submission;
+       int guc_log_level;
        int use_mmio_flip;
        int mmio_debug;
        bool verbose_state_checks;
@@ -2626,7 +2640,6 @@ extern void i915_driver_preclose(struct drm_device *dev,
                                 struct drm_file *file);
 extern void i915_driver_postclose(struct drm_device *dev,
                                  struct drm_file *file);
-extern int i915_driver_device_is_agp(struct drm_device * dev);
 #ifdef CONFIG_COMPAT
 extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
                              unsigned long arg);
@@ -2646,7 +2659,7 @@ void intel_hpd_irq_handler(struct drm_device *dev, u32 pin_mask, u32 long_mask);
 void intel_hpd_init(struct drm_i915_private *dev_priv);
 void intel_hpd_init_work(struct drm_i915_private *dev_priv);
 void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
-enum port intel_hpd_pin_to_port(enum hpd_pin pin);
+bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port);
 
 /* i915_irq.c */
 void i915_queue_hangcheck(struct drm_device *dev);
@@ -2758,6 +2771,8 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
                         const struct drm_i915_gem_object_ops *ops);
 struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
                                                  size_t size);
+struct drm_i915_gem_object *i915_gem_object_create_from_data(
+               struct drm_device *dev, const void *data, size_t size);
 void i915_init_vm(struct drm_i915_private *dev_priv,
                  struct i915_address_space *vm);
 void i915_gem_free_object(struct drm_gem_object *obj);
@@ -2864,11 +2879,6 @@ static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req,
 
 int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno);
 int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno);
-int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj);
-int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj);
-
-bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj);
-void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj);
 
 struct drm_i915_gem_request *
 i915_gem_find_active_request(struct intel_engine_cs *ring);
@@ -2966,8 +2976,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
 struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
                                struct drm_gem_object *gem_obj, int flags);
 
-void i915_gem_restore_fences(struct drm_device *dev);
-
 unsigned long
 i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
                              const struct i915_ggtt_view *view);
@@ -3062,6 +3070,19 @@ i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj)
        i915_gem_object_ggtt_unpin_view(obj, &i915_ggtt_view_normal);
 }
 
+/* i915_gem_fence.c */
+int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj);
+int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj);
+
+bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj);
+void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj);
+
+void i915_gem_restore_fences(struct drm_device *dev);
+
+void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
+void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj);
+void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj);
+
 /* i915_gem_context.c */
 int __must_check i915_gem_context_init(struct drm_device *dev);
 void i915_gem_context_fini(struct drm_device *dev);
@@ -3154,10 +3175,6 @@ static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_objec
                obj->tiling_mode != I915_TILING_NONE;
 }
 
-void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
-void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj);
-void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj);
-
 /* i915_gem_debug.c */
 #if WATCH_LISTS
 int i915_verify_lists(struct drm_device *dev);
@@ -3359,15 +3376,14 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
 #define I915_READ64(reg)       dev_priv->uncore.funcs.mmio_readq(dev_priv, (reg), true)
 
 #define I915_READ64_2x32(lower_reg, upper_reg) ({                      \
-               u32 upper = I915_READ(upper_reg);                       \
-               u32 lower = I915_READ(lower_reg);                       \
-               u32 tmp = I915_READ(upper_reg);                         \
-               if (upper != tmp) {                                     \
-                       upper = tmp;                                    \
-                       lower = I915_READ(lower_reg);                   \
-                       WARN_ON(I915_READ(upper_reg) != upper);         \
-               }                                                       \
-               (u64)upper << 32 | lower; })
+       u32 upper, lower, tmp;                                          \
+       tmp = I915_READ(upper_reg);                                     \
+       do {                                                            \
+               upper = tmp;                                            \
+               lower = I915_READ(lower_reg);                           \
+               tmp = I915_READ(upper_reg);                             \
+       } while (upper != tmp);                                         \
+       (u64)upper << 32 | lower; })
 
 #define POSTING_READ(reg)      (void)I915_READ_NOTRACE(reg)
 #define POSTING_READ16(reg)    (void)I915_READ16_NOTRACE(reg)
index d9f2701b45932e48c77fe0826158240e53c162ca..84f91bcc12f7946de23d71632cd3fbf66f62312e 100644 (file)
@@ -46,11 +46,6 @@ static void
 i915_gem_object_retire__write(struct drm_i915_gem_object *obj);
 static void
 i915_gem_object_retire__read(struct drm_i915_gem_object *obj, int ring);
-static void i915_gem_write_fence(struct drm_device *dev, int reg,
-                                struct drm_i915_gem_object *obj);
-static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
-                                        struct drm_i915_fence_reg *fence,
-                                        bool enable);
 
 static bool cpu_cache_is_coherent(struct drm_device *dev,
                                  enum i915_cache_level level)
@@ -66,18 +61,6 @@ static bool cpu_write_needs_clflush(struct drm_i915_gem_object *obj)
        return obj->pin_display;
 }
 
-static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
-{
-       if (obj->tiling_mode)
-               i915_gem_release_mmap(obj);
-
-       /* As we do not have an associated fence register, we will force
-        * a tiling change if we ever need to acquire one.
-        */
-       obj->fence_dirty = false;
-       obj->fence_reg = I915_FENCE_REG_NONE;
-}
-
 /* some bookkeeping */
 static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
                                  size_t size)
@@ -2402,6 +2385,13 @@ i915_gem_object_retire__read(struct drm_i915_gem_object *obj, int ring)
        if (obj->active)
                return;
 
+       /* Bump our place on the bound list to keep it roughly in LRU order
+        * so that we don't steal from recently used but inactive objects
+        * (unless we are forced to ofc!)
+        */
+       list_move_tail(&obj->global_list,
+                      &to_i915(obj->base.dev)->mm.bound_list);
+
        list_for_each_entry(vma, &obj->vma_list, vma_link) {
                if (!list_empty(&vma->mm_list))
                        list_move_tail(&vma->mm_list, &vma->vm->inactive_list);
@@ -2793,27 +2783,6 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
        }
 }
 
-void i915_gem_restore_fences(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-
-       for (i = 0; i < dev_priv->num_fence_regs; i++) {
-               struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
-
-               /*
-                * Commit delayed tiling changes if we have an object still
-                * attached to the fence, otherwise just clear the fence.
-                */
-               if (reg->obj) {
-                       i915_gem_object_update_fence(reg->obj, reg,
-                                                    reg->obj->tiling_mode);
-               } else {
-                       i915_gem_write_fence(dev, i, NULL);
-               }
-       }
-}
-
 void i915_gem_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3340,343 +3309,6 @@ int i915_gpu_idle(struct drm_device *dev)
        return 0;
 }
 
-static void i965_write_fence_reg(struct drm_device *dev, int reg,
-                                struct drm_i915_gem_object *obj)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int fence_reg;
-       int fence_pitch_shift;
-
-       if (INTEL_INFO(dev)->gen >= 6) {
-               fence_reg = FENCE_REG_SANDYBRIDGE_0;
-               fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT;
-       } else {
-               fence_reg = FENCE_REG_965_0;
-               fence_pitch_shift = I965_FENCE_PITCH_SHIFT;
-       }
-
-       fence_reg += reg * 8;
-
-       /* To w/a incoherency with non-atomic 64-bit register updates,
-        * we split the 64-bit update into two 32-bit writes. In order
-        * for a partial fence not to be evaluated between writes, we
-        * precede the update with write to turn off the fence register,
-        * and only enable the fence as the last step.
-        *
-        * For extra levels of paranoia, we make sure each step lands
-        * before applying the next step.
-        */
-       I915_WRITE(fence_reg, 0);
-       POSTING_READ(fence_reg);
-
-       if (obj) {
-               u32 size = i915_gem_obj_ggtt_size(obj);
-               uint64_t val;
-
-               /* Adjust fence size to match tiled area */
-               if (obj->tiling_mode != I915_TILING_NONE) {
-                       uint32_t row_size = obj->stride *
-                               (obj->tiling_mode == I915_TILING_Y ? 32 : 8);
-                       size = (size / row_size) * row_size;
-               }
-
-               val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) &
-                                0xfffff000) << 32;
-               val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000;
-               val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift;
-               if (obj->tiling_mode == I915_TILING_Y)
-                       val |= 1 << I965_FENCE_TILING_Y_SHIFT;
-               val |= I965_FENCE_REG_VALID;
-
-               I915_WRITE(fence_reg + 4, val >> 32);
-               POSTING_READ(fence_reg + 4);
-
-               I915_WRITE(fence_reg + 0, val);
-               POSTING_READ(fence_reg);
-       } else {
-               I915_WRITE(fence_reg + 4, 0);
-               POSTING_READ(fence_reg + 4);
-       }
-}
-
-static void i915_write_fence_reg(struct drm_device *dev, int reg,
-                                struct drm_i915_gem_object *obj)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 val;
-
-       if (obj) {
-               u32 size = i915_gem_obj_ggtt_size(obj);
-               int pitch_val;
-               int tile_width;
-
-               WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) ||
-                    (size & -size) != size ||
-                    (i915_gem_obj_ggtt_offset(obj) & (size - 1)),
-                    "object 0x%08lx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n",
-                    i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size);
-
-               if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
-                       tile_width = 128;
-               else
-                       tile_width = 512;
-
-               /* Note: pitch better be a power of two tile widths */
-               pitch_val = obj->stride / tile_width;
-               pitch_val = ffs(pitch_val) - 1;
-
-               val = i915_gem_obj_ggtt_offset(obj);
-               if (obj->tiling_mode == I915_TILING_Y)
-                       val |= 1 << I830_FENCE_TILING_Y_SHIFT;
-               val |= I915_FENCE_SIZE_BITS(size);
-               val |= pitch_val << I830_FENCE_PITCH_SHIFT;
-               val |= I830_FENCE_REG_VALID;
-       } else
-               val = 0;
-
-       if (reg < 8)
-               reg = FENCE_REG_830_0 + reg * 4;
-       else
-               reg = FENCE_REG_945_8 + (reg - 8) * 4;
-
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
-}
-
-static void i830_write_fence_reg(struct drm_device *dev, int reg,
-                               struct drm_i915_gem_object *obj)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t val;
-
-       if (obj) {
-               u32 size = i915_gem_obj_ggtt_size(obj);
-               uint32_t pitch_val;
-
-               WARN((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) ||
-                    (size & -size) != size ||
-                    (i915_gem_obj_ggtt_offset(obj) & (size - 1)),
-                    "object 0x%08lx not 512K or pot-size 0x%08x aligned\n",
-                    i915_gem_obj_ggtt_offset(obj), size);
-
-               pitch_val = obj->stride / 128;
-               pitch_val = ffs(pitch_val) - 1;
-
-               val = i915_gem_obj_ggtt_offset(obj);
-               if (obj->tiling_mode == I915_TILING_Y)
-                       val |= 1 << I830_FENCE_TILING_Y_SHIFT;
-               val |= I830_FENCE_SIZE_BITS(size);
-               val |= pitch_val << I830_FENCE_PITCH_SHIFT;
-               val |= I830_FENCE_REG_VALID;
-       } else
-               val = 0;
-
-       I915_WRITE(FENCE_REG_830_0 + reg * 4, val);
-       POSTING_READ(FENCE_REG_830_0 + reg * 4);
-}
-
-inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj)
-{
-       return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT;
-}
-
-static void i915_gem_write_fence(struct drm_device *dev, int reg,
-                                struct drm_i915_gem_object *obj)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       /* Ensure that all CPU reads are completed before installing a fence
-        * and all writes before removing the fence.
-        */
-       if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj))
-               mb();
-
-       WARN(obj && (!obj->stride || !obj->tiling_mode),
-            "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
-            obj->stride, obj->tiling_mode);
-
-       if (IS_GEN2(dev))
-               i830_write_fence_reg(dev, reg, obj);
-       else if (IS_GEN3(dev))
-               i915_write_fence_reg(dev, reg, obj);
-       else if (INTEL_INFO(dev)->gen >= 4)
-               i965_write_fence_reg(dev, reg, obj);
-
-       /* And similarly be paranoid that no direct access to this region
-        * is reordered to before the fence is installed.
-        */
-       if (i915_gem_object_needs_mb(obj))
-               mb();
-}
-
-static inline int fence_number(struct drm_i915_private *dev_priv,
-                              struct drm_i915_fence_reg *fence)
-{
-       return fence - dev_priv->fence_regs;
-}
-
-static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
-                                        struct drm_i915_fence_reg *fence,
-                                        bool enable)
-{
-       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-       int reg = fence_number(dev_priv, fence);
-
-       i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL);
-
-       if (enable) {
-               obj->fence_reg = reg;
-               fence->obj = obj;
-               list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
-       } else {
-               obj->fence_reg = I915_FENCE_REG_NONE;
-               fence->obj = NULL;
-               list_del_init(&fence->lru_list);
-       }
-       obj->fence_dirty = false;
-}
-
-static int
-i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
-{
-       if (obj->last_fenced_req) {
-               int ret = i915_wait_request(obj->last_fenced_req);
-               if (ret)
-                       return ret;
-
-               i915_gem_request_assign(&obj->last_fenced_req, NULL);
-       }
-
-       return 0;
-}
-
-int
-i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
-{
-       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-       struct drm_i915_fence_reg *fence;
-       int ret;
-
-       ret = i915_gem_object_wait_fence(obj);
-       if (ret)
-               return ret;
-
-       if (obj->fence_reg == I915_FENCE_REG_NONE)
-               return 0;
-
-       fence = &dev_priv->fence_regs[obj->fence_reg];
-
-       if (WARN_ON(fence->pin_count))
-               return -EBUSY;
-
-       i915_gem_object_fence_lost(obj);
-       i915_gem_object_update_fence(obj, fence, false);
-
-       return 0;
-}
-
-static struct drm_i915_fence_reg *
-i915_find_fence_reg(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_i915_fence_reg *reg, *avail;
-       int i;
-
-       /* First try to find a free reg */
-       avail = NULL;
-       for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
-               reg = &dev_priv->fence_regs[i];
-               if (!reg->obj)
-                       return reg;
-
-               if (!reg->pin_count)
-                       avail = reg;
-       }
-
-       if (avail == NULL)
-               goto deadlock;
-
-       /* None available, try to steal one or wait for a user to finish */
-       list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) {
-               if (reg->pin_count)
-                       continue;
-
-               return reg;
-       }
-
-deadlock:
-       /* Wait for completion of pending flips which consume fences */
-       if (intel_has_pending_fb_unpin(dev))
-               return ERR_PTR(-EAGAIN);
-
-       return ERR_PTR(-EDEADLK);
-}
-
-/**
- * i915_gem_object_get_fence - set up fencing for an object
- * @obj: object to map through a fence reg
- *
- * When mapping objects through the GTT, userspace wants to be able to write
- * to them without having to worry about swizzling if the object is tiled.
- * This function walks the fence regs looking for a free one for @obj,
- * stealing one if it can't find any.
- *
- * It then sets up the reg based on the object's properties: address, pitch
- * and tiling format.
- *
- * For an untiled surface, this removes any existing fence.
- */
-int
-i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
-{
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       bool enable = obj->tiling_mode != I915_TILING_NONE;
-       struct drm_i915_fence_reg *reg;
-       int ret;
-
-       /* Have we updated the tiling parameters upon the object and so
-        * will need to serialise the write to the associated fence register?
-        */
-       if (obj->fence_dirty) {
-               ret = i915_gem_object_wait_fence(obj);
-               if (ret)
-                       return ret;
-       }
-
-       /* Just update our place in the LRU if our fence is getting reused. */
-       if (obj->fence_reg != I915_FENCE_REG_NONE) {
-               reg = &dev_priv->fence_regs[obj->fence_reg];
-               if (!obj->fence_dirty) {
-                       list_move_tail(&reg->lru_list,
-                                      &dev_priv->mm.fence_list);
-                       return 0;
-               }
-       } else if (enable) {
-               if (WARN_ON(!obj->map_and_fenceable))
-                       return -EINVAL;
-
-               reg = i915_find_fence_reg(dev);
-               if (IS_ERR(reg))
-                       return PTR_ERR(reg);
-
-               if (reg->obj) {
-                       struct drm_i915_gem_object *old = reg->obj;
-
-                       ret = i915_gem_object_wait_fence(old);
-                       if (ret)
-                               return ret;
-
-                       i915_gem_object_fence_lost(old);
-               }
-       } else
-               return 0;
-
-       i915_gem_object_update_fence(obj, reg, enable);
-
-       return 0;
-}
-
 static bool i915_gem_valid_gtt_space(struct i915_vma *vma,
                                     unsigned long cache_level)
 {
@@ -4476,32 +4108,6 @@ i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj,
        --vma->pin_count;
 }
 
-bool
-i915_gem_object_pin_fence(struct drm_i915_gem_object *obj)
-{
-       if (obj->fence_reg != I915_FENCE_REG_NONE) {
-               struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-               struct i915_vma *ggtt_vma = i915_gem_obj_to_ggtt(obj);
-
-               WARN_ON(!ggtt_vma ||
-                       dev_priv->fence_regs[obj->fence_reg].pin_count >
-                       ggtt_vma->pin_count);
-               dev_priv->fence_regs[obj->fence_reg].pin_count++;
-               return true;
-       } else
-               return false;
-}
-
-void
-i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
-{
-       if (obj->fence_reg != I915_FENCE_REG_NONE) {
-               struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-               WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0);
-               dev_priv->fence_regs[obj->fence_reg].pin_count--;
-       }
-}
-
 int
 i915_gem_busy_ioctl(struct drm_device *dev, void *data,
                    struct drm_file *file)
@@ -5477,3 +5083,43 @@ bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj)
 
        return false;
 }
+
+/* Allocate a new GEM object and fill it with the supplied data */
+struct drm_i915_gem_object *
+i915_gem_object_create_from_data(struct drm_device *dev,
+                                const void *data, size_t size)
+{
+       struct drm_i915_gem_object *obj;
+       struct sg_table *sg;
+       size_t bytes;
+       int ret;
+
+       obj = i915_gem_alloc_object(dev, round_up(size, PAGE_SIZE));
+       if (IS_ERR_OR_NULL(obj))
+               return obj;
+
+       ret = i915_gem_object_set_to_cpu_domain(obj, true);
+       if (ret)
+               goto fail;
+
+       ret = i915_gem_object_get_pages(obj);
+       if (ret)
+               goto fail;
+
+       i915_gem_object_pin_pages(obj);
+       sg = obj->pages;
+       bytes = sg_copy_from_buffer(sg->sgl, sg->nents, (void *)data, size);
+       i915_gem_object_unpin_pages(obj);
+
+       if (WARN_ON(bytes != size)) {
+               DRM_ERROR("Incomplete copy, wrote %zu of %zu", bytes, size);
+               ret = -EFAULT;
+               goto fail;
+       }
+
+       return obj;
+
+fail:
+       drm_gem_object_unreference(&obj->base);
+       return ERR_PTR(ret);
+}
index b77a8f78c35a6c839c1002a6751a44d0460c47fd..8e893b354bccdfb5205dea4b4e3559d02225fe54 100644 (file)
@@ -287,6 +287,7 @@ err_unpin:
        if (is_global_default_ctx && ctx->legacy_hw_ctx.rcs_state)
                i915_gem_object_ggtt_unpin(ctx->legacy_hw_ctx.rcs_state);
 err_destroy:
+       idr_remove(&file_priv->context_idr, ctx->user_handle);
        i915_gem_context_unreference(ctx);
        return ERR_PTR(ret);
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c
new file mode 100644 (file)
index 0000000..af1f8c4
--- /dev/null
@@ -0,0 +1,787 @@
+/*
+ * 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 <drm/drmP.h>
+#include <drm/i915_drm.h>
+#include "i915_drv.h"
+
+/**
+ * DOC: fence register handling
+ *
+ * Important to avoid confusions: "fences" in the i915 driver are not execution
+ * fences used to track command completion but hardware detiler objects which
+ * wrap a given range of the global GTT. Each platform has only a fairly limited
+ * set of these objects.
+ *
+ * Fences are used to detile GTT memory mappings. They're also connected to the
+ * hardware frontbuffer render tracking and hence interract with frontbuffer
+ * conmpression. Furthermore on older platforms fences are required for tiled
+ * objects used by the display engine. They can also be used by the render
+ * engine - they're required for blitter commands and are optional for render
+ * commands. But on gen4+ both display (with the exception of fbc) and rendering
+ * have their own tiling state bits and don't need fences.
+ *
+ * Also note that fences only support X and Y tiling and hence can't be used for
+ * the fancier new tiling formats like W, Ys and Yf.
+ *
+ * Finally note that because fences are such a restricted resource they're
+ * dynamically associated with objects. Furthermore fence state is committed to
+ * the hardware lazily to avoid unecessary stalls on gen2/3. Therefore code must
+ * explictly call i915_gem_object_get_fence() to synchronize fencing status
+ * for cpu access. Also note that some code wants an unfenced view, for those
+ * cases the fence can be removed forcefully with i915_gem_object_put_fence().
+ *
+ * Internally these functions will synchronize with userspace access by removing
+ * CPU ptes into GTT mmaps (not the GTT ptes themselves) as needed.
+ */
+
+static void i965_write_fence_reg(struct drm_device *dev, int reg,
+                                struct drm_i915_gem_object *obj)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int fence_reg;
+       int fence_pitch_shift;
+
+       if (INTEL_INFO(dev)->gen >= 6) {
+               fence_reg = FENCE_REG_SANDYBRIDGE_0;
+               fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT;
+       } else {
+               fence_reg = FENCE_REG_965_0;
+               fence_pitch_shift = I965_FENCE_PITCH_SHIFT;
+       }
+
+       fence_reg += reg * 8;
+
+       /* To w/a incoherency with non-atomic 64-bit register updates,
+        * we split the 64-bit update into two 32-bit writes. In order
+        * for a partial fence not to be evaluated between writes, we
+        * precede the update with write to turn off the fence register,
+        * and only enable the fence as the last step.
+        *
+        * For extra levels of paranoia, we make sure each step lands
+        * before applying the next step.
+        */
+       I915_WRITE(fence_reg, 0);
+       POSTING_READ(fence_reg);
+
+       if (obj) {
+               u32 size = i915_gem_obj_ggtt_size(obj);
+               uint64_t val;
+
+               /* Adjust fence size to match tiled area */
+               if (obj->tiling_mode != I915_TILING_NONE) {
+                       uint32_t row_size = obj->stride *
+                               (obj->tiling_mode == I915_TILING_Y ? 32 : 8);
+                       size = (size / row_size) * row_size;
+               }
+
+               val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) &
+                                0xfffff000) << 32;
+               val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000;
+               val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift;
+               if (obj->tiling_mode == I915_TILING_Y)
+                       val |= 1 << I965_FENCE_TILING_Y_SHIFT;
+               val |= I965_FENCE_REG_VALID;
+
+               I915_WRITE(fence_reg + 4, val >> 32);
+               POSTING_READ(fence_reg + 4);
+
+               I915_WRITE(fence_reg + 0, val);
+               POSTING_READ(fence_reg);
+       } else {
+               I915_WRITE(fence_reg + 4, 0);
+               POSTING_READ(fence_reg + 4);
+       }
+}
+
+static void i915_write_fence_reg(struct drm_device *dev, int reg,
+                                struct drm_i915_gem_object *obj)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val;
+
+       if (obj) {
+               u32 size = i915_gem_obj_ggtt_size(obj);
+               int pitch_val;
+               int tile_width;
+
+               WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) ||
+                    (size & -size) != size ||
+                    (i915_gem_obj_ggtt_offset(obj) & (size - 1)),
+                    "object 0x%08lx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n",
+                    i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size);
+
+               if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
+                       tile_width = 128;
+               else
+                       tile_width = 512;
+
+               /* Note: pitch better be a power of two tile widths */
+               pitch_val = obj->stride / tile_width;
+               pitch_val = ffs(pitch_val) - 1;
+
+               val = i915_gem_obj_ggtt_offset(obj);
+               if (obj->tiling_mode == I915_TILING_Y)
+                       val |= 1 << I830_FENCE_TILING_Y_SHIFT;
+               val |= I915_FENCE_SIZE_BITS(size);
+               val |= pitch_val << I830_FENCE_PITCH_SHIFT;
+               val |= I830_FENCE_REG_VALID;
+       } else
+               val = 0;
+
+       if (reg < 8)
+               reg = FENCE_REG_830_0 + reg * 4;
+       else
+               reg = FENCE_REG_945_8 + (reg - 8) * 4;
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+}
+
+static void i830_write_fence_reg(struct drm_device *dev, int reg,
+                               struct drm_i915_gem_object *obj)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t val;
+
+       if (obj) {
+               u32 size = i915_gem_obj_ggtt_size(obj);
+               uint32_t pitch_val;
+
+               WARN((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) ||
+                    (size & -size) != size ||
+                    (i915_gem_obj_ggtt_offset(obj) & (size - 1)),
+                    "object 0x%08lx not 512K or pot-size 0x%08x aligned\n",
+                    i915_gem_obj_ggtt_offset(obj), size);
+
+               pitch_val = obj->stride / 128;
+               pitch_val = ffs(pitch_val) - 1;
+
+               val = i915_gem_obj_ggtt_offset(obj);
+               if (obj->tiling_mode == I915_TILING_Y)
+                       val |= 1 << I830_FENCE_TILING_Y_SHIFT;
+               val |= I830_FENCE_SIZE_BITS(size);
+               val |= pitch_val << I830_FENCE_PITCH_SHIFT;
+               val |= I830_FENCE_REG_VALID;
+       } else
+               val = 0;
+
+       I915_WRITE(FENCE_REG_830_0 + reg * 4, val);
+       POSTING_READ(FENCE_REG_830_0 + reg * 4);
+}
+
+inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj)
+{
+       return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT;
+}
+
+static void i915_gem_write_fence(struct drm_device *dev, int reg,
+                                struct drm_i915_gem_object *obj)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /* Ensure that all CPU reads are completed before installing a fence
+        * and all writes before removing the fence.
+        */
+       if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj))
+               mb();
+
+       WARN(obj && (!obj->stride || !obj->tiling_mode),
+            "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
+            obj->stride, obj->tiling_mode);
+
+       if (IS_GEN2(dev))
+               i830_write_fence_reg(dev, reg, obj);
+       else if (IS_GEN3(dev))
+               i915_write_fence_reg(dev, reg, obj);
+       else if (INTEL_INFO(dev)->gen >= 4)
+               i965_write_fence_reg(dev, reg, obj);
+
+       /* And similarly be paranoid that no direct access to this region
+        * is reordered to before the fence is installed.
+        */
+       if (i915_gem_object_needs_mb(obj))
+               mb();
+}
+
+static inline int fence_number(struct drm_i915_private *dev_priv,
+                              struct drm_i915_fence_reg *fence)
+{
+       return fence - dev_priv->fence_regs;
+}
+
+static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
+                                        struct drm_i915_fence_reg *fence,
+                                        bool enable)
+{
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       int reg = fence_number(dev_priv, fence);
+
+       i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL);
+
+       if (enable) {
+               obj->fence_reg = reg;
+               fence->obj = obj;
+               list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
+       } else {
+               obj->fence_reg = I915_FENCE_REG_NONE;
+               fence->obj = NULL;
+               list_del_init(&fence->lru_list);
+       }
+       obj->fence_dirty = false;
+}
+
+static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
+{
+       if (obj->tiling_mode)
+               i915_gem_release_mmap(obj);
+
+       /* As we do not have an associated fence register, we will force
+        * a tiling change if we ever need to acquire one.
+        */
+       obj->fence_dirty = false;
+       obj->fence_reg = I915_FENCE_REG_NONE;
+}
+
+static int
+i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
+{
+       if (obj->last_fenced_req) {
+               int ret = i915_wait_request(obj->last_fenced_req);
+               if (ret)
+                       return ret;
+
+               i915_gem_request_assign(&obj->last_fenced_req, NULL);
+       }
+
+       return 0;
+}
+
+/**
+ * i915_gem_object_put_fence - force-remove fence for an object
+ * @obj: object to map through a fence reg
+ *
+ * This function force-removes any fence from the given object, which is useful
+ * if the kernel wants to do untiled GTT access.
+ *
+ * Returns:
+ *
+ * 0 on success, negative error code on failure.
+ */
+int
+i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
+{
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       struct drm_i915_fence_reg *fence;
+       int ret;
+
+       ret = i915_gem_object_wait_fence(obj);
+       if (ret)
+               return ret;
+
+       if (obj->fence_reg == I915_FENCE_REG_NONE)
+               return 0;
+
+       fence = &dev_priv->fence_regs[obj->fence_reg];
+
+       if (WARN_ON(fence->pin_count))
+               return -EBUSY;
+
+       i915_gem_object_fence_lost(obj);
+       i915_gem_object_update_fence(obj, fence, false);
+
+       return 0;
+}
+
+static struct drm_i915_fence_reg *
+i915_find_fence_reg(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_fence_reg *reg, *avail;
+       int i;
+
+       /* First try to find a free reg */
+       avail = NULL;
+       for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
+               reg = &dev_priv->fence_regs[i];
+               if (!reg->obj)
+                       return reg;
+
+               if (!reg->pin_count)
+                       avail = reg;
+       }
+
+       if (avail == NULL)
+               goto deadlock;
+
+       /* None available, try to steal one or wait for a user to finish */
+       list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) {
+               if (reg->pin_count)
+                       continue;
+
+               return reg;
+       }
+
+deadlock:
+       /* Wait for completion of pending flips which consume fences */
+       if (intel_has_pending_fb_unpin(dev))
+               return ERR_PTR(-EAGAIN);
+
+       return ERR_PTR(-EDEADLK);
+}
+
+/**
+ * i915_gem_object_get_fence - set up fencing for an object
+ * @obj: object to map through a fence reg
+ *
+ * When mapping objects through the GTT, userspace wants to be able to write
+ * to them without having to worry about swizzling if the object is tiled.
+ * This function walks the fence regs looking for a free one for @obj,
+ * stealing one if it can't find any.
+ *
+ * It then sets up the reg based on the object's properties: address, pitch
+ * and tiling format.
+ *
+ * For an untiled surface, this removes any existing fence.
+ *
+ * Returns:
+ *
+ * 0 on success, negative error code on failure.
+ */
+int
+i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
+{
+       struct drm_device *dev = obj->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       bool enable = obj->tiling_mode != I915_TILING_NONE;
+       struct drm_i915_fence_reg *reg;
+       int ret;
+
+       /* Have we updated the tiling parameters upon the object and so
+        * will need to serialise the write to the associated fence register?
+        */
+       if (obj->fence_dirty) {
+               ret = i915_gem_object_wait_fence(obj);
+               if (ret)
+                       return ret;
+       }
+
+       /* Just update our place in the LRU if our fence is getting reused. */
+       if (obj->fence_reg != I915_FENCE_REG_NONE) {
+               reg = &dev_priv->fence_regs[obj->fence_reg];
+               if (!obj->fence_dirty) {
+                       list_move_tail(&reg->lru_list,
+                                      &dev_priv->mm.fence_list);
+                       return 0;
+               }
+       } else if (enable) {
+               if (WARN_ON(!obj->map_and_fenceable))
+                       return -EINVAL;
+
+               reg = i915_find_fence_reg(dev);
+               if (IS_ERR(reg))
+                       return PTR_ERR(reg);
+
+               if (reg->obj) {
+                       struct drm_i915_gem_object *old = reg->obj;
+
+                       ret = i915_gem_object_wait_fence(old);
+                       if (ret)
+                               return ret;
+
+                       i915_gem_object_fence_lost(old);
+               }
+       } else
+               return 0;
+
+       i915_gem_object_update_fence(obj, reg, enable);
+
+       return 0;
+}
+
+/**
+ * i915_gem_object_pin_fence - pin fencing state
+ * @obj: object to pin fencing for
+ *
+ * This pins the fencing state (whether tiled or untiled) to make sure the
+ * object is ready to be used as a scanout target. Fencing status must be
+ * synchronize first by calling i915_gem_object_get_fence():
+ *
+ * The resulting fence pin reference must be released again with
+ * i915_gem_object_unpin_fence().
+ *
+ * Returns:
+ *
+ * True if the object has a fence, false otherwise.
+ */
+bool
+i915_gem_object_pin_fence(struct drm_i915_gem_object *obj)
+{
+       if (obj->fence_reg != I915_FENCE_REG_NONE) {
+               struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+               struct i915_vma *ggtt_vma = i915_gem_obj_to_ggtt(obj);
+
+               WARN_ON(!ggtt_vma ||
+                       dev_priv->fence_regs[obj->fence_reg].pin_count >
+                       ggtt_vma->pin_count);
+               dev_priv->fence_regs[obj->fence_reg].pin_count++;
+               return true;
+       } else
+               return false;
+}
+
+/**
+ * i915_gem_object_unpin_fence - unpin fencing state
+ * @obj: object to unpin fencing for
+ *
+ * This releases the fence pin reference acquired through
+ * i915_gem_object_pin_fence. It will handle both objects with and without an
+ * attached fence correctly, callers do not need to distinguish this.
+ */
+void
+i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
+{
+       if (obj->fence_reg != I915_FENCE_REG_NONE) {
+               struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+               WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0);
+               dev_priv->fence_regs[obj->fence_reg].pin_count--;
+       }
+}
+
+/**
+ * i915_gem_restore_fences - restore fence state
+ * @dev: DRM device
+ *
+ * Restore the hw fence state to match the software tracking again, to be called
+ * after a gpu reset and on resume.
+ */
+void i915_gem_restore_fences(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+
+       for (i = 0; i < dev_priv->num_fence_regs; i++) {
+               struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
+
+               /*
+                * Commit delayed tiling changes if we have an object still
+                * attached to the fence, otherwise just clear the fence.
+                */
+               if (reg->obj) {
+                       i915_gem_object_update_fence(reg->obj, reg,
+                                                    reg->obj->tiling_mode);
+               } else {
+                       i915_gem_write_fence(dev, i, NULL);
+               }
+       }
+}
+
+/**
+ * DOC: tiling swizzling details
+ *
+ * The idea behind tiling is to increase cache hit rates by rearranging
+ * pixel data so that a group of pixel accesses are in the same cacheline.
+ * Performance improvement from doing this on the back/depth buffer are on
+ * the order of 30%.
+ *
+ * Intel architectures make this somewhat more complicated, though, by
+ * adjustments made to addressing of data when the memory is in interleaved
+ * mode (matched pairs of DIMMS) to improve memory bandwidth.
+ * For interleaved memory, the CPU sends every sequential 64 bytes
+ * to an alternate memory channel so it can get the bandwidth from both.
+ *
+ * The GPU also rearranges its accesses for increased bandwidth to interleaved
+ * memory, and it matches what the CPU does for non-tiled.  However, when tiled
+ * it does it a little differently, since one walks addresses not just in the
+ * X direction but also Y.  So, along with alternating channels when bit
+ * 6 of the address flips, it also alternates when other bits flip --  Bits 9
+ * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines)
+ * are common to both the 915 and 965-class hardware.
+ *
+ * The CPU also sometimes XORs in higher bits as well, to improve
+ * bandwidth doing strided access like we do so frequently in graphics.  This
+ * is called "Channel XOR Randomization" in the MCH documentation.  The result
+ * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address
+ * decode.
+ *
+ * All of this bit 6 XORing has an effect on our memory management,
+ * as we need to make sure that the 3d driver can correctly address object
+ * contents.
+ *
+ * If we don't have interleaved memory, all tiling is safe and no swizzling is
+ * required.
+ *
+ * When bit 17 is XORed in, we simply refuse to tile at all.  Bit
+ * 17 is not just a page offset, so as we page an objet out and back in,
+ * individual pages in it will have different bit 17 addresses, resulting in
+ * each 64 bytes being swapped with its neighbor!
+ *
+ * Otherwise, if interleaved, we have to tell the 3d driver what the address
+ * swizzling it needs to do is, since it's writing with the CPU to the pages
+ * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the
+ * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling
+ * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order
+ * to match what the GPU expects.
+ */
+
+/**
+ * i915_gem_detect_bit_6_swizzle - detect bit 6 swizzling pattern
+ * @dev: DRM device
+ *
+ * Detects bit 6 swizzling of address lookup between IGD access and CPU
+ * access through main memory.
+ */
+void
+i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+       uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+
+       if (INTEL_INFO(dev)->gen >= 8 || IS_VALLEYVIEW(dev)) {
+               /*
+                * On BDW+, swizzling is not used. We leave the CPU memory
+                * controller in charge of optimizing memory accesses without
+                * the extra address manipulation GPU side.
+                *
+                * VLV and CHV don't have GPU swizzling.
+                */
+               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+       } else if (INTEL_INFO(dev)->gen >= 6) {
+               if (dev_priv->preserve_bios_swizzle) {
+                       if (I915_READ(DISP_ARB_CTL) &
+                           DISP_TILE_SURFACE_SWIZZLING) {
+                               swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+                               swizzle_y = I915_BIT_6_SWIZZLE_9;
+                       } else {
+                               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+                               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+                       }
+               } else {
+                       uint32_t dimm_c0, dimm_c1;
+                       dimm_c0 = I915_READ(MAD_DIMM_C0);
+                       dimm_c1 = I915_READ(MAD_DIMM_C1);
+                       dimm_c0 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK;
+                       dimm_c1 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK;
+                       /* Enable swizzling when the channels are populated
+                        * with identically sized dimms. We don't need to check
+                        * the 3rd channel because no cpu with gpu attached
+                        * ships in that configuration. Also, swizzling only
+                        * makes sense for 2 channels anyway. */
+                       if (dimm_c0 == dimm_c1) {
+                               swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+                               swizzle_y = I915_BIT_6_SWIZZLE_9;
+                       } else {
+                               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+                               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+                       }
+               }
+       } else if (IS_GEN5(dev)) {
+               /* On Ironlake whatever DRAM config, GPU always do
+                * same swizzling setup.
+                */
+               swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+               swizzle_y = I915_BIT_6_SWIZZLE_9;
+       } else if (IS_GEN2(dev)) {
+               /* As far as we know, the 865 doesn't have these bit 6
+                * swizzling issues.
+                */
+               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+       } else if (IS_MOBILE(dev) || (IS_GEN3(dev) && !IS_G33(dev))) {
+               uint32_t dcc;
+
+               /* On 9xx chipsets, channel interleave by the CPU is
+                * determined by DCC.  For single-channel, neither the CPU
+                * nor the GPU do swizzling.  For dual channel interleaved,
+                * the GPU's interleave is bit 9 and 10 for X tiled, and bit
+                * 9 for Y tiled.  The CPU's interleave is independent, and
+                * can be based on either bit 11 (haven't seen this yet) or
+                * bit 17 (common).
+                */
+               dcc = I915_READ(DCC);
+               switch (dcc & DCC_ADDRESSING_MODE_MASK) {
+               case DCC_ADDRESSING_MODE_SINGLE_CHANNEL:
+               case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC:
+                       swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+                       swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+                       break;
+               case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
+                       if (dcc & DCC_CHANNEL_XOR_DISABLE) {
+                               /* This is the base swizzling by the GPU for
+                                * tiled buffers.
+                                */
+                               swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+                               swizzle_y = I915_BIT_6_SWIZZLE_9;
+                       } else if ((dcc & DCC_CHANNEL_XOR_BIT_17) == 0) {
+                               /* Bit 11 swizzling by the CPU in addition. */
+                               swizzle_x = I915_BIT_6_SWIZZLE_9_10_11;
+                               swizzle_y = I915_BIT_6_SWIZZLE_9_11;
+                       } else {
+                               /* Bit 17 swizzling by the CPU in addition. */
+                               swizzle_x = I915_BIT_6_SWIZZLE_9_10_17;
+                               swizzle_y = I915_BIT_6_SWIZZLE_9_17;
+                       }
+                       break;
+               }
+
+               /* check for L-shaped memory aka modified enhanced addressing */
+               if (IS_GEN4(dev)) {
+                       uint32_t ddc2 = I915_READ(DCC2);
+
+                       if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE))
+                               dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES;
+               }
+
+               if (dcc == 0xffffffff) {
+                       DRM_ERROR("Couldn't read from MCHBAR.  "
+                                 "Disabling tiling.\n");
+                       swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+                       swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+               }
+       } else {
+               /* The 965, G33, and newer, have a very flexible memory
+                * configuration.  It will enable dual-channel mode
+                * (interleaving) on as much memory as it can, and the GPU
+                * will additionally sometimes enable different bit 6
+                * swizzling for tiled objects from the CPU.
+                *
+                * Here's what I found on the G965:
+                *    slot fill         memory size  swizzling
+                * 0A   0B   1A   1B    1-ch   2-ch
+                * 512  0    0    0     512    0     O
+                * 512  0    512  0     16     1008  X
+                * 512  0    0    512   16     1008  X
+                * 0    512  0    512   16     1008  X
+                * 1024 1024 1024 0     2048   1024  O
+                *
+                * We could probably detect this based on either the DRB
+                * matching, which was the case for the swizzling required in
+                * the table above, or from the 1-ch value being less than
+                * the minimum size of a rank.
+                */
+               if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
+                       swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+                       swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+               } else {
+                       swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+                       swizzle_y = I915_BIT_6_SWIZZLE_9;
+               }
+       }
+
+       dev_priv->mm.bit_6_swizzle_x = swizzle_x;
+       dev_priv->mm.bit_6_swizzle_y = swizzle_y;
+}
+
+/*
+ * Swap every 64 bytes of this page around, to account for it having a new
+ * bit 17 of its physical address and therefore being interpreted differently
+ * by the GPU.
+ */
+static void
+i915_gem_swizzle_page(struct page *page)
+{
+       char temp[64];
+       char *vaddr;
+       int i;
+
+       vaddr = kmap(page);
+
+       for (i = 0; i < PAGE_SIZE; i += 128) {
+               memcpy(temp, &vaddr[i], 64);
+               memcpy(&vaddr[i], &vaddr[i + 64], 64);
+               memcpy(&vaddr[i + 64], temp, 64);
+       }
+
+       kunmap(page);
+}
+
+/**
+ * i915_gem_object_do_bit_17_swizzle - fixup bit 17 swizzling
+ * @obj: i915 GEM buffer object
+ *
+ * This function fixes up the swizzling in case any page frame number for this
+ * object has changed in bit 17 since that state has been saved with
+ * i915_gem_object_save_bit_17_swizzle().
+ *
+ * This is called when pinning backing storage again, since the kernel is free
+ * to move unpinned backing storage around (either by directly moving pages or
+ * by swapping them out and back in again).
+ */
+void
+i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
+{
+       struct sg_page_iter sg_iter;
+       int i;
+
+       if (obj->bit_17 == NULL)
+               return;
+
+       i = 0;
+       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
+               struct page *page = sg_page_iter_page(&sg_iter);
+               char new_bit_17 = page_to_phys(page) >> 17;
+               if ((new_bit_17 & 0x1) !=
+                   (test_bit(i, obj->bit_17) != 0)) {
+                       i915_gem_swizzle_page(page);
+                       set_page_dirty(page);
+               }
+               i++;
+       }
+}
+
+/**
+ * i915_gem_object_save_bit_17_swizzle - save bit 17 swizzling
+ * @obj: i915 GEM buffer object
+ *
+ * This function saves the bit 17 of each page frame number so that swizzling
+ * can be fixed up later on with i915_gem_object_do_bit_17_swizzle(). This must
+ * be called before the backing storage can be unpinned.
+ */
+void
+i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
+{
+       struct sg_page_iter sg_iter;
+       int page_count = obj->base.size >> PAGE_SHIFT;
+       int i;
+
+       if (obj->bit_17 == NULL) {
+               obj->bit_17 = kcalloc(BITS_TO_LONGS(page_count),
+                                     sizeof(long), GFP_KERNEL);
+               if (obj->bit_17 == NULL) {
+                       DRM_ERROR("Failed to allocate memory for bit 17 "
+                                 "record\n");
+                       return;
+               }
+       }
+
+       i = 0;
+       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
+               if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17))
+                       __set_bit(i, obj->bit_17);
+               else
+                       __clear_bit(i, obj->bit_17);
+               i++;
+       }
+}
index c2a291e09bd98222a20239881e8d5cbca6a49d6a..96054a560f4f8da59f40a1fc532013a1b7c5b374 100644 (file)
@@ -2003,6 +2003,17 @@ static int ggtt_bind_vma(struct i915_vma *vma,
                vma->vm->insert_entries(vma->vm, pages,
                                        vma->node.start,
                                        cache_level, pte_flags);
+
+               /* Note the inconsistency here is due to absence of the
+                * aliasing ppgtt on gen4 and earlier. Though we always
+                * request PIN_USER for execbuffer (translated to LOCAL_BIND),
+                * without the appgtt, we cannot honour that request and so
+                * must substitute it with a global binding. Since we do this
+                * behind the upper layers back, we need to explicitly set
+                * the bound flag ourselves.
+                */
+               vma->bound |= GLOBAL_BIND;
+
        }
 
        if (dev_priv->mm.aliasing_ppgtt && flags & LOCAL_BIND) {
index a0201fc94d256431b41aa5ca26dbef0fae565257..5026a6267a88034b3cae18acc0674952a711521a 100644 (file)
@@ -73,6 +73,24 @@ free_gem:
        return ret;
 }
 
+/*
+ * Macro to add commands to auxiliary batch.
+ * This macro only checks for page overflow before inserting the commands,
+ * this is sufficient as the null state generator makes the final batch
+ * with two passes to build command and state separately. At this point
+ * the size of both are known and it compacts them by relocating the state
+ * right after the commands taking care of aligment so we should sufficient
+ * space below them for adding new commands.
+ */
+#define OUT_BATCH(batch, i, val)                               \
+       do {                                                    \
+               if (WARN_ON((i) >= PAGE_SIZE / sizeof(u32))) {  \
+                       ret = -ENOSPC;                          \
+                       goto err_out;                           \
+               }                                               \
+               (batch)[(i)++] = (val);                         \
+       } while(0)
+
 static int render_state_setup(struct render_state *so)
 {
        const struct intel_renderstate_rodata *rodata = so->rodata;
@@ -96,8 +114,10 @@ static int render_state_setup(struct render_state *so)
                        s = lower_32_bits(r);
                        if (so->gen >= 8) {
                                if (i + 1 >= rodata->batch_items ||
-                                   rodata->batch[i + 1] != 0)
-                                       return -EINVAL;
+                                   rodata->batch[i + 1] != 0) {
+                                       ret = -EINVAL;
+                                       goto err_out;
+                               }
 
                                d[i++] = s;
                                s = upper_32_bits(r);
@@ -108,6 +128,21 @@ static int render_state_setup(struct render_state *so)
 
                d[i++] = s;
        }
+
+       while (i % CACHELINE_DWORDS)
+               OUT_BATCH(d, i, MI_NOOP);
+
+       so->aux_batch_offset = i * sizeof(u32);
+
+       OUT_BATCH(d, i, MI_BATCH_BUFFER_END);
+       so->aux_batch_size = (i * sizeof(u32)) - so->aux_batch_offset;
+
+       /*
+        * Since we are sending length, we need to strictly conform to
+        * all requirements. For Gen2 this must be a multiple of 8.
+        */
+       so->aux_batch_size = ALIGN(so->aux_batch_size, 8);
+
        kunmap(page);
 
        ret = i915_gem_object_set_to_gtt_domain(so->obj, false);
@@ -120,8 +155,14 @@ static int render_state_setup(struct render_state *so)
        }
 
        return 0;
+
+err_out:
+       kunmap(page);
+       return ret;
 }
 
+#undef OUT_BATCH
+
 void i915_gem_render_state_fini(struct render_state *so)
 {
        i915_gem_object_ggtt_unpin(so->obj);
@@ -170,6 +211,16 @@ int i915_gem_render_state_init(struct drm_i915_gem_request *req)
        if (ret)
                goto out;
 
+       if (so.aux_batch_size > 8) {
+               ret = req->ring->dispatch_execbuffer(req,
+                                                    (so.ggtt_offset +
+                                                     so.aux_batch_offset),
+                                                    so.aux_batch_size,
+                                                    I915_DISPATCH_SECURE);
+               if (ret)
+                       goto out;
+       }
+
        i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req);
 
 out:
index 7aa73728178ace3a5e03851ace0e753d0d21a4c8..e641bb093a903bba18e02cd0cd156e6070a40a62 100644 (file)
@@ -37,6 +37,8 @@ struct render_state {
        struct drm_i915_gem_object *obj;
        u64 ggtt_offset;
        int gen;
+       u32 aux_batch_size;
+       u32 aux_batch_offset;
 };
 
 int i915_gem_render_state_init(struct drm_i915_gem_request *req);
index ed682a9a9cbba2a0d79af9369a3761e39d6b5e1c..a36cb95ec798ec8a8a3e09da884cf6528d84c126 100644 (file)
@@ -186,11 +186,103 @@ void i915_gem_cleanup_stolen(struct drm_device *dev)
        drm_mm_takedown(&dev_priv->mm.stolen);
 }
 
+static void gen6_get_stolen_reserved(struct drm_i915_private *dev_priv,
+                                    unsigned long *base, unsigned long *size)
+{
+       uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED);
+
+       *base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
+
+       switch (reg_val & GEN6_STOLEN_RESERVED_SIZE_MASK) {
+       case GEN6_STOLEN_RESERVED_1M:
+               *size = 1024 * 1024;
+               break;
+       case GEN6_STOLEN_RESERVED_512K:
+               *size = 512 * 1024;
+               break;
+       case GEN6_STOLEN_RESERVED_256K:
+               *size = 256 * 1024;
+               break;
+       case GEN6_STOLEN_RESERVED_128K:
+               *size = 128 * 1024;
+               break;
+       default:
+               *size = 1024 * 1024;
+               MISSING_CASE(reg_val & GEN6_STOLEN_RESERVED_SIZE_MASK);
+       }
+}
+
+static void gen7_get_stolen_reserved(struct drm_i915_private *dev_priv,
+                                    unsigned long *base, unsigned long *size)
+{
+       uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED);
+
+       *base = reg_val & GEN7_STOLEN_RESERVED_ADDR_MASK;
+
+       switch (reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK) {
+       case GEN7_STOLEN_RESERVED_1M:
+               *size = 1024 * 1024;
+               break;
+       case GEN7_STOLEN_RESERVED_256K:
+               *size = 256 * 1024;
+               break;
+       default:
+               *size = 1024 * 1024;
+               MISSING_CASE(reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK);
+       }
+}
+
+static void gen8_get_stolen_reserved(struct drm_i915_private *dev_priv,
+                                    unsigned long *base, unsigned long *size)
+{
+       uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED);
+
+       *base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
+
+       switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) {
+       case GEN8_STOLEN_RESERVED_1M:
+               *size = 1024 * 1024;
+               break;
+       case GEN8_STOLEN_RESERVED_2M:
+               *size = 2 * 1024 * 1024;
+               break;
+       case GEN8_STOLEN_RESERVED_4M:
+               *size = 4 * 1024 * 1024;
+               break;
+       case GEN8_STOLEN_RESERVED_8M:
+               *size = 8 * 1024 * 1024;
+               break;
+       default:
+               *size = 8 * 1024 * 1024;
+               MISSING_CASE(reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK);
+       }
+}
+
+static void bdw_get_stolen_reserved(struct drm_i915_private *dev_priv,
+                                   unsigned long *base, unsigned long *size)
+{
+       uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED);
+       unsigned long stolen_top;
+
+       stolen_top = dev_priv->mm.stolen_base + dev_priv->gtt.stolen_size;
+
+       *base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
+
+       /* On these platforms, the register doesn't have a size field, so the
+        * size is the distance between the base and the top of the stolen
+        * memory. We also have the genuine case where base is zero and there's
+        * nothing reserved. */
+       if (*base == 0)
+               *size = 0;
+       else
+               *size = stolen_top - *base;
+}
+
 int i915_gem_init_stolen(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 tmp;
-       int bios_reserved = 0;
+       unsigned long reserved_total, reserved_base, reserved_size;
+       unsigned long stolen_top;
 
        mutex_init(&dev_priv->mm.stolen_lock);
 
@@ -208,26 +300,61 @@ int i915_gem_init_stolen(struct drm_device *dev)
        if (dev_priv->mm.stolen_base == 0)
                return 0;
 
-       DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n",
-                     dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base);
-
-       if (INTEL_INFO(dev)->gen >= 8) {
-               tmp = I915_READ(GEN7_BIOS_RESERVED);
-               tmp >>= GEN8_BIOS_RESERVED_SHIFT;
-               tmp &= GEN8_BIOS_RESERVED_MASK;
-               bios_reserved = (1024*1024) << tmp;
-       } else if (IS_GEN7(dev)) {
-               tmp = I915_READ(GEN7_BIOS_RESERVED);
-               bios_reserved = tmp & GEN7_BIOS_RESERVED_256K ?
-                       256*1024 : 1024*1024;
+       stolen_top = dev_priv->mm.stolen_base + dev_priv->gtt.stolen_size;
+
+       switch (INTEL_INFO(dev_priv)->gen) {
+       case 2:
+       case 3:
+       case 4:
+       case 5:
+               /* Assume the gen6 maximum for the older platforms. */
+               reserved_size = 1024 * 1024;
+               reserved_base = stolen_top - reserved_size;
+               break;
+       case 6:
+               gen6_get_stolen_reserved(dev_priv, &reserved_base,
+                                        &reserved_size);
+               break;
+       case 7:
+               gen7_get_stolen_reserved(dev_priv, &reserved_base,
+                                        &reserved_size);
+               break;
+       default:
+               if (IS_BROADWELL(dev_priv) || IS_SKYLAKE(dev_priv))
+                       bdw_get_stolen_reserved(dev_priv, &reserved_base,
+                                               &reserved_size);
+               else
+                       gen8_get_stolen_reserved(dev_priv, &reserved_base,
+                                                &reserved_size);
+               break;
+       }
+
+       /* It is possible for the reserved base to be zero, but the register
+        * field for size doesn't have a zero option. */
+       if (reserved_base == 0) {
+               reserved_size = 0;
+               reserved_base = stolen_top;
        }
 
-       if (WARN_ON(bios_reserved > dev_priv->gtt.stolen_size))
+       if (reserved_base < dev_priv->mm.stolen_base ||
+           reserved_base + reserved_size > stolen_top) {
+               DRM_DEBUG_KMS("Stolen reserved area [0x%08lx - 0x%08lx] outside stolen memory [0x%08lx - 0x%08lx]\n",
+                             reserved_base, reserved_base + reserved_size,
+                             dev_priv->mm.stolen_base, stolen_top);
                return 0;
+       }
+
+       /* It is possible for the reserved area to end before the end of stolen
+        * memory, so just consider the start. */
+       reserved_total = stolen_top - reserved_base;
+
+       DRM_DEBUG_KMS("Memory reserved for graphics device: %luK, usable: %luK\n",
+                     dev_priv->gtt.stolen_size >> 10,
+                     (dev_priv->gtt.stolen_size - reserved_total) >> 10);
 
        /* Basic memrange allocator for stolen space */
        drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size -
-                   bios_reserved);
+                   reserved_total);
 
        return 0;
 }
index 633bd1fcab6925881048e7310f9aa40e4f9db868..8a6717cc265c6c0a062d8cae9d4dc966356fa028 100644 (file)
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
-/** @file i915_gem_tiling.c
- *
- * Support for managing tiling state of buffer objects.
- *
- * The idea behind tiling is to increase cache hit rates by rearranging
- * pixel data so that a group of pixel accesses are in the same cacheline.
- * Performance improvement from doing this on the back/depth buffer are on
- * the order of 30%.
- *
- * Intel architectures make this somewhat more complicated, though, by
- * adjustments made to addressing of data when the memory is in interleaved
- * mode (matched pairs of DIMMS) to improve memory bandwidth.
- * For interleaved memory, the CPU sends every sequential 64 bytes
- * to an alternate memory channel so it can get the bandwidth from both.
- *
- * The GPU also rearranges its accesses for increased bandwidth to interleaved
- * memory, and it matches what the CPU does for non-tiled.  However, when tiled
- * it does it a little differently, since one walks addresses not just in the
- * X direction but also Y.  So, along with alternating channels when bit
- * 6 of the address flips, it also alternates when other bits flip --  Bits 9
- * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines)
- * are common to both the 915 and 965-class hardware.
- *
- * The CPU also sometimes XORs in higher bits as well, to improve
- * bandwidth doing strided access like we do so frequently in graphics.  This
- * is called "Channel XOR Randomization" in the MCH documentation.  The result
- * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address
- * decode.
+/**
+ * DOC: buffer object tiling
  *
- * All of this bit 6 XORing has an effect on our memory management,
- * as we need to make sure that the 3d driver can correctly address object
- * contents.
+ * i915_gem_set_tiling() and i915_gem_get_tiling() is the userspace interface to
+ * declare fence register requirements.
  *
- * If we don't have interleaved memory, all tiling is safe and no swizzling is
- * required.
+ * In principle GEM doesn't care at all about the internal data layout of an
+ * object, and hence it also doesn't care about tiling or swizzling. There's two
+ * exceptions:
  *
- * When bit 17 is XORed in, we simply refuse to tile at all.  Bit
- * 17 is not just a page offset, so as we page an objet out and back in,
- * individual pages in it will have different bit 17 addresses, resulting in
- * each 64 bytes being swapped with its neighbor!
+ * - For X and Y tiling the hardware provides detilers for CPU access, so called
+ *   fences. Since there's only a limited amount of them the kernel must manage
+ *   these, and therefore userspace must tell the kernel the object tiling if it
+ *   wants to use fences for detiling.
+ * - On gen3 and gen4 platforms have a swizzling pattern for tiled objects which
+ *   depends upon the physical page frame number. When swapping such objects the
+ *   page frame number might change and the kernel must be able to fix this up
+ *   and hence now the tiling. Note that on a subset of platforms with
+ *   asymmetric memory channel population the swizzling pattern changes in an
+ *   unknown way, and for those the kernel simply forbids swapping completely.
  *
- * Otherwise, if interleaved, we have to tell the 3d driver what the address
- * swizzling it needs to do is, since it's writing with the CPU to the pages
- * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the
- * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling
- * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order
- * to match what the GPU expects.
- */
-
-/**
- * Detects bit 6 swizzling of address lookup between IGD access and CPU
- * access through main memory.
+ * Since neither of this applies for new tiling layouts on modern platforms like
+ * W, Ys and Yf tiling GEM only allows object tiling to be set to X or Y tiled.
+ * Anything else can be handled in userspace entirely without the kernel's
+ * invovlement.
  */
-void
-i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
-       uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
-
-       if (INTEL_INFO(dev)->gen >= 8 || IS_VALLEYVIEW(dev)) {
-               /*
-                * On BDW+, swizzling is not used. We leave the CPU memory
-                * controller in charge of optimizing memory accesses without
-                * the extra address manipulation GPU side.
-                *
-                * VLV and CHV don't have GPU swizzling.
-                */
-               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
-               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
-       } else if (INTEL_INFO(dev)->gen >= 6) {
-               if (dev_priv->preserve_bios_swizzle) {
-                       if (I915_READ(DISP_ARB_CTL) &
-                           DISP_TILE_SURFACE_SWIZZLING) {
-                               swizzle_x = I915_BIT_6_SWIZZLE_9_10;
-                               swizzle_y = I915_BIT_6_SWIZZLE_9;
-                       } else {
-                               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
-                               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
-                       }
-               } else {
-                       uint32_t dimm_c0, dimm_c1;
-                       dimm_c0 = I915_READ(MAD_DIMM_C0);
-                       dimm_c1 = I915_READ(MAD_DIMM_C1);
-                       dimm_c0 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK;
-                       dimm_c1 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK;
-                       /* Enable swizzling when the channels are populated
-                        * with identically sized dimms. We don't need to check
-                        * the 3rd channel because no cpu with gpu attached
-                        * ships in that configuration. Also, swizzling only
-                        * makes sense for 2 channels anyway. */
-                       if (dimm_c0 == dimm_c1) {
-                               swizzle_x = I915_BIT_6_SWIZZLE_9_10;
-                               swizzle_y = I915_BIT_6_SWIZZLE_9;
-                       } else {
-                               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
-                               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
-                       }
-               }
-       } else if (IS_GEN5(dev)) {
-               /* On Ironlake whatever DRAM config, GPU always do
-                * same swizzling setup.
-                */
-               swizzle_x = I915_BIT_6_SWIZZLE_9_10;
-               swizzle_y = I915_BIT_6_SWIZZLE_9;
-       } else if (IS_GEN2(dev)) {
-               /* As far as we know, the 865 doesn't have these bit 6
-                * swizzling issues.
-                */
-               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
-               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
-       } else if (IS_MOBILE(dev) || (IS_GEN3(dev) && !IS_G33(dev))) {
-               uint32_t dcc;
-
-               /* On 9xx chipsets, channel interleave by the CPU is
-                * determined by DCC.  For single-channel, neither the CPU
-                * nor the GPU do swizzling.  For dual channel interleaved,
-                * the GPU's interleave is bit 9 and 10 for X tiled, and bit
-                * 9 for Y tiled.  The CPU's interleave is independent, and
-                * can be based on either bit 11 (haven't seen this yet) or
-                * bit 17 (common).
-                */
-               dcc = I915_READ(DCC);
-               switch (dcc & DCC_ADDRESSING_MODE_MASK) {
-               case DCC_ADDRESSING_MODE_SINGLE_CHANNEL:
-               case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC:
-                       swizzle_x = I915_BIT_6_SWIZZLE_NONE;
-                       swizzle_y = I915_BIT_6_SWIZZLE_NONE;
-                       break;
-               case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
-                       if (dcc & DCC_CHANNEL_XOR_DISABLE) {
-                               /* This is the base swizzling by the GPU for
-                                * tiled buffers.
-                                */
-                               swizzle_x = I915_BIT_6_SWIZZLE_9_10;
-                               swizzle_y = I915_BIT_6_SWIZZLE_9;
-                       } else if ((dcc & DCC_CHANNEL_XOR_BIT_17) == 0) {
-                               /* Bit 11 swizzling by the CPU in addition. */
-                               swizzle_x = I915_BIT_6_SWIZZLE_9_10_11;
-                               swizzle_y = I915_BIT_6_SWIZZLE_9_11;
-                       } else {
-                               /* Bit 17 swizzling by the CPU in addition. */
-                               swizzle_x = I915_BIT_6_SWIZZLE_9_10_17;
-                               swizzle_y = I915_BIT_6_SWIZZLE_9_17;
-                       }
-                       break;
-               }
-
-               /* check for L-shaped memory aka modified enhanced addressing */
-               if (IS_GEN4(dev)) {
-                       uint32_t ddc2 = I915_READ(DCC2);
-
-                       if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE))
-                               dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES;
-               }
-
-               if (dcc == 0xffffffff) {
-                       DRM_ERROR("Couldn't read from MCHBAR.  "
-                                 "Disabling tiling.\n");
-                       swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
-                       swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
-               }
-       } else {
-               /* The 965, G33, and newer, have a very flexible memory
-                * configuration.  It will enable dual-channel mode
-                * (interleaving) on as much memory as it can, and the GPU
-                * will additionally sometimes enable different bit 6
-                * swizzling for tiled objects from the CPU.
-                *
-                * Here's what I found on the G965:
-                *    slot fill         memory size  swizzling
-                * 0A   0B   1A   1B    1-ch   2-ch
-                * 512  0    0    0     512    0     O
-                * 512  0    512  0     16     1008  X
-                * 512  0    0    512   16     1008  X
-                * 0    512  0    512   16     1008  X
-                * 1024 1024 1024 0     2048   1024  O
-                *
-                * We could probably detect this based on either the DRB
-                * matching, which was the case for the swizzling required in
-                * the table above, or from the 1-ch value being less than
-                * the minimum size of a rank.
-                */
-               if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
-                       swizzle_x = I915_BIT_6_SWIZZLE_NONE;
-                       swizzle_y = I915_BIT_6_SWIZZLE_NONE;
-               } else {
-                       swizzle_x = I915_BIT_6_SWIZZLE_9_10;
-                       swizzle_y = I915_BIT_6_SWIZZLE_9;
-               }
-       }
-
-       dev_priv->mm.bit_6_swizzle_x = swizzle_x;
-       dev_priv->mm.bit_6_swizzle_y = swizzle_y;
-}
 
 /* Check pitch constriants for all chips & tiling formats */
 static bool
@@ -313,8 +144,18 @@ i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode)
 }
 
 /**
+ * i915_gem_set_tiling - IOCTL handler to set tiling mode
+ * @dev: DRM device
+ * @data: data pointer for the ioctl
+ * @file: DRM file for the ioctl call
+ *
  * Sets the tiling mode of an object, returning the required swizzling of
  * bit 6 of addresses in the object.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
  */
 int
 i915_gem_set_tiling(struct drm_device *dev, void *data,
@@ -432,7 +273,17 @@ err:
 }
 
 /**
+ * i915_gem_get_tiling - IOCTL handler to get tiling mode
+ * @dev: DRM device
+ * @data: data pointer for the ioctl
+ * @file: DRM file for the ioctl call
+ *
  * Returns the current tiling mode and required bit 6 swizzling for the object.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
  */
 int
 i915_gem_get_tiling(struct drm_device *dev, void *data,
@@ -464,7 +315,10 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
        }
 
        /* Hide bit 17 from the user -- see comment in i915_gem_set_tiling */
-       args->phys_swizzle_mode = args->swizzle_mode;
+       if (dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES)
+               args->phys_swizzle_mode = I915_BIT_6_SWIZZLE_UNKNOWN;
+       else
+               args->phys_swizzle_mode = args->swizzle_mode;
        if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17)
                args->swizzle_mode = I915_BIT_6_SWIZZLE_9;
        if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17)
@@ -475,75 +329,3 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
 
        return 0;
 }
-
-/**
- * Swap every 64 bytes of this page around, to account for it having a new
- * bit 17 of its physical address and therefore being interpreted differently
- * by the GPU.
- */
-static void
-i915_gem_swizzle_page(struct page *page)
-{
-       char temp[64];
-       char *vaddr;
-       int i;
-
-       vaddr = kmap(page);
-
-       for (i = 0; i < PAGE_SIZE; i += 128) {
-               memcpy(temp, &vaddr[i], 64);
-               memcpy(&vaddr[i], &vaddr[i + 64], 64);
-               memcpy(&vaddr[i + 64], temp, 64);
-       }
-
-       kunmap(page);
-}
-
-void
-i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
-{
-       struct sg_page_iter sg_iter;
-       int i;
-
-       if (obj->bit_17 == NULL)
-               return;
-
-       i = 0;
-       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
-               struct page *page = sg_page_iter_page(&sg_iter);
-               char new_bit_17 = page_to_phys(page) >> 17;
-               if ((new_bit_17 & 0x1) !=
-                   (test_bit(i, obj->bit_17) != 0)) {
-                       i915_gem_swizzle_page(page);
-                       set_page_dirty(page);
-               }
-               i++;
-       }
-}
-
-void
-i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
-{
-       struct sg_page_iter sg_iter;
-       int page_count = obj->base.size >> PAGE_SHIFT;
-       int i;
-
-       if (obj->bit_17 == NULL) {
-               obj->bit_17 = kcalloc(BITS_TO_LONGS(page_count),
-                                     sizeof(long), GFP_KERNEL);
-               if (obj->bit_17 == NULL) {
-                       DRM_ERROR("Failed to allocate memory for bit 17 "
-                                 "record\n");
-                       return;
-               }
-       }
-
-       i = 0;
-       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
-               if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17))
-                       __set_bit(i, obj->bit_17);
-               else
-                       __clear_bit(i, obj->bit_17);
-               i++;
-       }
-}
index 6f4256918f7694804f992cd2466db250d7490ad0..41d0739e6fdfa9474a21b63b754c9000a7b33421 100644 (file)
@@ -369,6 +369,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        err_printf(m, "Reset count: %u\n", error->reset_count);
        err_printf(m, "Suspend count: %u\n", error->suspend_count);
        err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device);
+       err_printf(m, "IOMMU enabled?: %d\n", error->iommu);
        err_printf(m, "EIR: 0x%08x\n", error->eir);
        err_printf(m, "IER: 0x%08x\n", error->ier);
        if (INTEL_INFO(dev)->gen >= 8) {
@@ -1266,6 +1267,10 @@ static void i915_error_capture_msg(struct drm_device *dev,
 static void i915_capture_gen_state(struct drm_i915_private *dev_priv,
                                   struct drm_i915_error_state *error)
 {
+       error->iommu = -1;
+#ifdef CONFIG_INTEL_IOMMU
+       error->iommu = intel_iommu_gfx_mapped;
+#endif
        error->reset_count = i915_reset_count(&dev_priv->gpu_error);
        error->suspend_count = dev_priv->suspend_count;
 }
diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h
new file mode 100644 (file)
index 0000000..ccdc6c8
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright Â© 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#ifndef _I915_GUC_REG_H_
+#define _I915_GUC_REG_H_
+
+/* Definitions of GuC H/W registers, bits, etc */
+
+#define GUC_STATUS                     0xc000
+#define   GS_BOOTROM_SHIFT             1
+#define   GS_BOOTROM_MASK                (0x7F << GS_BOOTROM_SHIFT)
+#define   GS_BOOTROM_RSA_FAILED                  (0x50 << GS_BOOTROM_SHIFT)
+#define   GS_UKERNEL_SHIFT             8
+#define   GS_UKERNEL_MASK                (0xFF << GS_UKERNEL_SHIFT)
+#define   GS_UKERNEL_LAPIC_DONE                  (0x30 << GS_UKERNEL_SHIFT)
+#define   GS_UKERNEL_DPC_ERROR           (0x60 << GS_UKERNEL_SHIFT)
+#define   GS_UKERNEL_READY               (0xF0 << GS_UKERNEL_SHIFT)
+#define   GS_MIA_SHIFT                 16
+#define   GS_MIA_MASK                    (0x07 << GS_MIA_SHIFT)
+
+#define GUC_WOPCM_SIZE                 0xc050
+#define   GUC_WOPCM_SIZE_VALUE           (0x80 << 12)  /* 512KB */
+#define GUC_WOPCM_OFFSET               0x80000         /* 512KB */
+
+#define SOFT_SCRATCH(n)                        (0xc180 + ((n) * 4))
+
+#define UOS_RSA_SCRATCH_0              0xc200
+#define DMA_ADDR_0_LOW                 0xc300
+#define DMA_ADDR_0_HIGH                        0xc304
+#define DMA_ADDR_1_LOW                 0xc308
+#define DMA_ADDR_1_HIGH                        0xc30c
+#define   DMA_ADDRESS_SPACE_WOPCM        (7 << 16)
+#define   DMA_ADDRESS_SPACE_GTT                  (8 << 16)
+#define DMA_COPY_SIZE                  0xc310
+#define DMA_CTRL                       0xc314
+#define   UOS_MOVE                       (1<<4)
+#define   START_DMA                      (1<<0)
+#define DMA_GUC_WOPCM_OFFSET           0xc340
+
+#define GEN8_GT_PM_CONFIG              0x138140
+#define GEN9_GT_PM_CONFIG              0x13816c
+#define   GEN8_GT_DOORBELL_ENABLE        (1<<0)
+
+#define GEN8_GTCR                      0x4274
+#define   GEN8_GTCR_INVALIDATE           (1<<0)
+
+#define GUC_ARAT_C6DIS                 0xA178
+
+#define GUC_SHIM_CONTROL               0xc064
+#define   GUC_DISABLE_SRAM_INIT_TO_ZEROES      (1<<0)
+#define   GUC_ENABLE_READ_CACHE_LOGIC          (1<<1)
+#define   GUC_ENABLE_MIA_CACHING               (1<<2)
+#define   GUC_GEN10_MSGCH_ENABLE               (1<<4)
+#define   GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA  (1<<9)
+#define   GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA (1<<10)
+#define   GUC_ENABLE_MIA_CLOCK_GATING          (1<<15)
+#define   GUC_GEN10_SHIM_WC_ENABLE             (1<<21)
+
+#define GUC_SHIM_CONTROL_VALUE (GUC_DISABLE_SRAM_INIT_TO_ZEROES        | \
+                                GUC_ENABLE_READ_CACHE_LOGIC            | \
+                                GUC_ENABLE_MIA_CACHING                 | \
+                                GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA    | \
+                                GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA)
+
+#define HOST2GUC_INTERRUPT             0xc4c8
+#define   HOST2GUC_TRIGGER               (1<<0)
+
+#define DRBMISC1                       0x1984
+#define   DOORBELL_ENABLE                (1<<0)
+
+#define GEN8_DRBREGL(x)                        (0x1000 + (x) * 8)
+#define   GEN8_DRB_VALID                 (1<<0)
+#define GEN8_DRBREGU(x)                        (GEN8_DRBREGL(x) + 4)
+
+#define DE_GUCRMR                      0x44054
+
+#define GUC_BCS_RCS_IER                        0xC550
+#define GUC_VCS2_VCS1_IER              0xC554
+#define GUC_WD_VECS_IER                        0xC558
+#define GUC_PM_P24C_IER                        0xC55C
+
+#endif
index d87f173a0179aca7e702dfcc6282aaad59fefa96..1118c39281f98cc272b23bcbded120c7ecdd4502 100644 (file)
@@ -1227,6 +1227,22 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
        return ret;
 }
 
+static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
+{
+       switch (port) {
+       case PORT_A:
+               return val & BXT_PORTA_HOTPLUG_LONG_DETECT;
+       case PORT_B:
+               return val & PORTB_HOTPLUG_LONG_DETECT;
+       case PORT_C:
+               return val & PORTC_HOTPLUG_LONG_DETECT;
+       case PORT_D:
+               return val & PORTD_HOTPLUG_LONG_DETECT;
+       default:
+               return false;
+       }
+}
+
 static bool pch_port_hotplug_long_detect(enum port port, u32 val)
 {
        switch (port) {
@@ -1256,9 +1272,10 @@ static bool i9xx_port_hotplug_long_detect(enum port port, u32 val)
 }
 
 /* Get a bit mask of pins that have triggered, and which ones may be long. */
-static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
+static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
                             u32 hotplug_trigger, u32 dig_hotplug_reg,
-                            const u32 hpd[HPD_NUM_PINS])
+                            const u32 hpd[HPD_NUM_PINS],
+                            bool long_pulse_detect(enum port port, u32 val))
 {
        enum port port;
        int i;
@@ -1272,8 +1289,10 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
 
                *pin_mask |= BIT(i);
 
-               port = intel_hpd_pin_to_port(i);
-               if (pch_port_hotplug_long_detect(port, dig_hotplug_reg))
+               if (!intel_hpd_pin_to_port(i, &port))
+                       continue;
+
+               if (long_pulse_detect(port, dig_hotplug_reg))
                        *long_mask |= BIT(i);
        }
 
@@ -1282,34 +1301,6 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
 
 }
 
-/* Get a bit mask of pins that have triggered, and which ones may be long. */
-static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
-                             u32 hotplug_trigger, const u32 hpd[HPD_NUM_PINS])
-{
-       enum port port;
-       int i;
-
-       *pin_mask = 0;
-       *long_mask = 0;
-
-       if (!hotplug_trigger)
-               return;
-
-       for_each_hpd_pin(i) {
-               if ((hpd[i] & hotplug_trigger) == 0)
-                       continue;
-
-               *pin_mask |= BIT(i);
-
-               port = intel_hpd_pin_to_port(i);
-               if (i9xx_port_hotplug_long_detect(port, hotplug_trigger))
-                       *long_mask |= BIT(i);
-       }
-
-       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, pins 0x%08x\n",
-                        hotplug_trigger, *pin_mask);
-}
-
 static void gmbus_irq_handler(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1547,7 +1538,9 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev)
        if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
                u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
 
-               i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_g4x);
+               intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+                                  hotplug_trigger, hpd_status_g4x,
+                                  i9xx_port_hotplug_long_detect);
                intel_hpd_irq_handler(dev, pin_mask, long_mask);
 
                if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
@@ -1555,7 +1548,9 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev)
        } else {
                u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
-               i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_i915);
+               intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+                                  hotplug_trigger, hpd_status_g4x,
+                                  i9xx_port_hotplug_long_detect);
                intel_hpd_irq_handler(dev, pin_mask, long_mask);
        }
 }
@@ -1662,8 +1657,9 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
                dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
                I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
 
-               pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
-                                dig_hotplug_reg, hpd_ibx);
+               intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+                                  dig_hotplug_reg, hpd_ibx,
+                                  pch_port_hotplug_long_detect);
                intel_hpd_irq_handler(dev, pin_mask, long_mask);
        }
 
@@ -1763,8 +1759,10 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 
                dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
                I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
-               pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
-                                dig_hotplug_reg, hpd_cpt);
+
+               intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+                                  dig_hotplug_reg, hpd_cpt,
+                                  pch_port_hotplug_long_detect);
                intel_hpd_irq_handler(dev, pin_mask, long_mask);
        }
 
@@ -1981,7 +1979,8 @@ static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status)
        /* Clear sticky bits in hpd status */
        I915_WRITE(BXT_HOTPLUG_CTL, hp_control);
 
-       pch_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, hpd_bxt);
+       intel_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control,
+                          hpd_bxt, bxt_port_hotplug_long_detect);
        intel_hpd_irq_handler(dev, pin_mask, long_mask);
 }
 
index 5f4e7295295ff4904a7207f839abd912f77f0340..5ae4b0aba56412e3c7d8560c5fe1d1484ae00675 100644 (file)
@@ -52,6 +52,8 @@ struct i915_params i915 __read_mostly = {
        .mmio_debug = 0,
        .verbose_state_checks = 1,
        .edp_vswing = 0,
+       .enable_guc_submission = false,
+       .guc_log_level = -1,
 };
 
 module_param_named(modeset, i915.modeset, int, 0400);
@@ -181,3 +183,10 @@ MODULE_PARM_DESC(edp_vswing,
                 "Ignore/Override vswing pre-emph table selection from VBT "
                 "(0=use value from vbt [default], 1=low power swing(200mV),"
                 "2=default swing(400mV))");
+
+module_param_named_unsafe(enable_guc_submission, i915.enable_guc_submission, bool, 0400);
+MODULE_PARM_DESC(enable_guc_submission, "Enable GuC submission (default:false)");
+
+module_param_named(guc_log_level, i915.guc_log_level, int, 0400);
+MODULE_PARM_DESC(guc_log_level,
+       "GuC firmware logging level (-1:disabled (default), 0-3:enabled)");
index e9a95df639f0e48653c200ecd5085eb5808a71eb..8e46c348366bc867c7b81ed9ccdd72d7bc57c2fc 100644 (file)
 #define GAB_CTL                                0x24000
 #define   GAB_CTL_CONT_AFTER_PAGEFAULT (1<<8)
 
-#define GEN7_BIOS_RESERVED             0x1082C0
-#define GEN7_BIOS_RESERVED_1M          (0 << 5)
-#define GEN7_BIOS_RESERVED_256K                (1 << 5)
-#define GEN8_BIOS_RESERVED_SHIFT       7
-#define GEN7_BIOS_RESERVED_MASK        0x1
-#define GEN8_BIOS_RESERVED_MASK        0x3
-
+#define GEN6_STOLEN_RESERVED           0x1082C0
+#define GEN6_STOLEN_RESERVED_ADDR_MASK (0xFFF << 20)
+#define GEN7_STOLEN_RESERVED_ADDR_MASK (0x3FFF << 18)
+#define GEN6_STOLEN_RESERVED_SIZE_MASK (3 << 4)
+#define GEN6_STOLEN_RESERVED_1M                (0 << 4)
+#define GEN6_STOLEN_RESERVED_512K      (1 << 4)
+#define GEN6_STOLEN_RESERVED_256K      (2 << 4)
+#define GEN6_STOLEN_RESERVED_128K      (3 << 4)
+#define GEN7_STOLEN_RESERVED_SIZE_MASK (1 << 5)
+#define GEN7_STOLEN_RESERVED_1M                (0 << 5)
+#define GEN7_STOLEN_RESERVED_256K      (1 << 5)
+#define GEN8_STOLEN_RESERVED_SIZE_MASK (3 << 7)
+#define GEN8_STOLEN_RESERVED_1M                (0 << 7)
+#define GEN8_STOLEN_RESERVED_2M                (1 << 7)
+#define GEN8_STOLEN_RESERVED_4M                (2 << 7)
+#define GEN8_STOLEN_RESERVED_8M                (3 << 7)
 
 /* VGA stuff */
 
@@ -5985,6 +5994,11 @@ enum skl_disp_power_wells {
 
 /* digital port hotplug */
 #define PCH_PORT_HOTPLUG        0xc4030                /* SHOTPLUG_CTL */
+#define BXT_PORTA_HOTPLUG_ENABLE       (1 << 28)
+#define BXT_PORTA_HOTPLUG_STATUS_MASK  (0x3 << 24)
+#define  BXT_PORTA_HOTPLUG_NO_DETECT   (0 << 24)
+#define  BXT_PORTA_HOTPLUG_SHORT_DETECT        (1 << 24)
+#define  BXT_PORTA_HOTPLUG_LONG_DETECT (2 << 24)
 #define PORTD_HOTPLUG_ENABLE            (1 << 20)
 #define PORTD_PULSE_DURATION_2ms        (0)
 #define PORTD_PULSE_DURATION_4_5ms      (1 << 18)
@@ -6846,6 +6860,9 @@ enum skl_disp_power_wells {
 #define GEN7_MISCCPCTL                 (0x9424)
 #define   GEN7_DOP_CLOCK_GATE_ENABLE   (1<<0)
 
+#define GEN8_GARBCNTL                   0xB004
+#define   GEN9_GAPS_TSV_CREDIT_DISABLE  (1<<7)
+
 /* IVYBRIDGE DPF */
 #define GEN7_L3CDERRST1                        0xB008 /* L3CD Error Status 1 */
 #define HSW_L3CDERRST11                        0xB208 /* L3CD Error Status register 1 slice 1 */
index 2ff9eb00fdec688b3ba9c8a618b404d321927c17..8e46149bafdd2380c6d075ca30cbc967d1c2a1e6 100644 (file)
@@ -886,6 +886,17 @@ err:
        memset(dev_priv->vbt.dsi.sequence, 0, sizeof(dev_priv->vbt.dsi.sequence));
 }
 
+static u8 translate_iboost(u8 val)
+{
+       static const u8 mapping[] = { 1, 3, 7 }; /* See VBT spec */
+
+       if (val >= ARRAY_SIZE(mapping)) {
+               DRM_DEBUG_KMS("Unsupported I_boost value found in VBT (%d), display may not work properly\n", val);
+               return 0;
+       }
+       return mapping[val];
+}
+
 static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
                           const struct bdb_header *bdb)
 {
@@ -968,13 +979,28 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
        }
 
        if (is_dp) {
-               if (aux_channel == 0x40 && port != PORT_A)
+               if (port == PORT_E) {
+                       info->alternate_aux_channel = aux_channel;
+                       /* if DDIE share aux channel with other port, then
+                        * DP couldn't exist on the shared port. Otherwise
+                        * they share the same aux channel and system
+                        * couldn't communicate with them seperately. */
+                       if (aux_channel == DP_AUX_A)
+                               dev_priv->vbt.ddi_port_info[PORT_A].supports_dp = 0;
+                       else if (aux_channel == DP_AUX_B)
+                               dev_priv->vbt.ddi_port_info[PORT_B].supports_dp = 0;
+                       else if (aux_channel == DP_AUX_C)
+                               dev_priv->vbt.ddi_port_info[PORT_C].supports_dp = 0;
+                       else if (aux_channel == DP_AUX_D)
+                               dev_priv->vbt.ddi_port_info[PORT_D].supports_dp = 0;
+               }
+               else if (aux_channel == DP_AUX_A && port != PORT_A)
                        DRM_DEBUG_KMS("Unexpected AUX channel for port A\n");
-               if (aux_channel == 0x10 && port != PORT_B)
+               else if (aux_channel == DP_AUX_B && port != PORT_B)
                        DRM_DEBUG_KMS("Unexpected AUX channel for port B\n");
-               if (aux_channel == 0x20 && port != PORT_C)
+               else if (aux_channel == DP_AUX_C && port != PORT_C)
                        DRM_DEBUG_KMS("Unexpected AUX channel for port C\n");
-               if (aux_channel == 0x30 && port != PORT_D)
+               else if (aux_channel == DP_AUX_D && port != PORT_D)
                        DRM_DEBUG_KMS("Unexpected AUX channel for port D\n");
        }
 
@@ -986,6 +1012,16 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
                              hdmi_level_shift);
                info->hdmi_level_shift = hdmi_level_shift;
        }
+
+       /* Parse the I_boost config for SKL and above */
+       if (bdb->version >= 196 && (child->common.flags_1 & IBOOST_ENABLE)) {
+               info->dp_boost_level = translate_iboost(child->common.iboost_level & 0xF);
+               DRM_DEBUG_KMS("VBT (e)DP boost level for port %c: %d\n",
+                             port_name(port), info->dp_boost_level);
+               info->hdmi_boost_level = translate_iboost(child->common.iboost_level >> 4);
+               DRM_DEBUG_KMS("VBT HDMI boost level for port %c: %d\n",
+                             port_name(port), info->hdmi_boost_level);
+       }
 }
 
 static void parse_ddi_ports(struct drm_i915_private *dev_priv,
@@ -1015,15 +1051,34 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
        const union child_device_config *p_child;
        union child_device_config *child_dev_ptr;
        int i, child_device_num, count;
-       u16     block_size;
+       u8 expected_size;
+       u16 block_size;
 
        p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
        if (!p_defs) {
                DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
                return;
        }
-       if (p_defs->child_dev_size < sizeof(*p_child)) {
-               DRM_ERROR("General definiton block child device size is too small.\n");
+       if (bdb->version < 195) {
+               expected_size = 33;
+       } else if (bdb->version == 195) {
+               expected_size = 37;
+       } else if (bdb->version <= 197) {
+               expected_size = 38;
+       } else {
+               expected_size = 38;
+               DRM_DEBUG_DRIVER("Expected child_device_config size for BDB version %u not known; assuming %u\n",
+                                expected_size, bdb->version);
+       }
+
+       if (expected_size > sizeof(*p_child)) {
+               DRM_ERROR("child_device_config cannot fit in p_child\n");
+               return;
+       }
+
+       if (p_defs->child_dev_size != expected_size) {
+               DRM_ERROR("Size mismatch; child_device_config size=%u (expected %u); bdb->version: %u\n",
+                         p_defs->child_dev_size, expected_size, bdb->version);
                return;
        }
        /* get the block size of general definitions */
@@ -1070,7 +1125,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
 
                child_dev_ptr = dev_priv->vbt.child_dev + count;
                count++;
-               memcpy(child_dev_ptr, p_child, sizeof(*p_child));
+               memcpy(child_dev_ptr, p_child, p_defs->child_dev_size);
        }
        return;
 }
index f7ad6a585129a311ec003392e5de46c887f303a8..6d909efbf43f3a52655551f71ab91f683ecb16bf 100644 (file)
@@ -231,6 +231,10 @@ struct old_child_dev_config {
 /* This one contains field offsets that are known to be common for all BDB
  * versions. Notice that the meaning of the contents contents may still change,
  * but at least the offsets are consistent. */
+
+/* Definitions for flags_1 */
+#define IBOOST_ENABLE (1<<3)
+
 struct common_child_dev_config {
        u16 handle;
        u16 device_type;
@@ -239,8 +243,13 @@ struct common_child_dev_config {
        u8 not_common2[2];
        u8 ddc_pin;
        u16 edid_ptr;
+       u8 obsolete;
+       u8 flags_1;
+       u8 not_common3[13];
+       u8 iboost_level;
 } __packed;
 
+
 /* This field changes depending on the BDB version, so the most reliable way to
  * read it is by checking the BDB version and reading the raw pointer. */
 union child_device_config {
index 521af2c069cb6aed90e379501d3fbc39c24df6e9..af5e43bef4a41003437a7f1f2979992d065193ac 100644 (file)
@@ -236,53 +236,6 @@ static void intel_enable_crt(struct intel_encoder *encoder)
        intel_crt_set_dpms(encoder, crt->connector->base.dpms);
 }
 
-/* Special dpms function to support cloning between dvo/sdvo/crt. */
-static void intel_crt_dpms(struct drm_connector *connector, int mode)
-{
-       struct drm_device *dev = connector->dev;
-       struct intel_encoder *encoder = intel_attached_encoder(connector);
-       struct drm_crtc *crtc;
-       int old_dpms;
-
-       /* PCH platforms and VLV only support on/off. */
-       if (INTEL_INFO(dev)->gen >= 5 && mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
-
-       if (mode == connector->dpms)
-               return;
-
-       old_dpms = connector->dpms;
-       connector->dpms = mode;
-
-       /* Only need to change hw state when actually enabled */
-       crtc = encoder->base.crtc;
-       if (!crtc) {
-               encoder->connectors_active = false;
-               return;
-       }
-
-       /* We need the pipe to run for anything but OFF. */
-       if (mode == DRM_MODE_DPMS_OFF)
-               encoder->connectors_active = false;
-       else
-               encoder->connectors_active = true;
-
-       /* We call connector dpms manually below in case pipe dpms doesn't
-        * change due to cloning. */
-       if (mode < old_dpms) {
-               /* From off to on, enable the pipe first. */
-               intel_crtc_update_dpms(crtc);
-
-               intel_crt_set_dpms(encoder, mode);
-       } else {
-               intel_crt_set_dpms(encoder, mode);
-
-               intel_crtc_update_dpms(crtc);
-       }
-
-       intel_modeset_check_state(connector->dev);
-}
-
 static enum drm_mode_status
 intel_crt_mode_valid(struct drm_connector *connector,
                     struct drm_display_mode *mode)
@@ -798,7 +751,7 @@ static void intel_crt_reset(struct drm_connector *connector)
 
 static const struct drm_connector_funcs intel_crt_connector_funcs = {
        .reset = intel_crt_reset,
-       .dpms = intel_crt_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .detect = intel_crt_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = intel_crt_destroy,
index 6d8a7bf06dfccba963705750f3881407c78a5c78..ba1ae031e6fd47ff7873fe739a4efd5e5c5fddac 100644 (file)
@@ -244,7 +244,7 @@ void intel_csr_load_status_set(struct drm_i915_private *dev_priv,
 void intel_csr_load_program(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       __be32 *payload = dev_priv->csr.dmc_payload;
+       u32 *payload = dev_priv->csr.dmc_payload;
        uint32_t i, fw_size;
 
        if (!IS_GEN9(dev)) {
@@ -256,7 +256,7 @@ void intel_csr_load_program(struct drm_device *dev)
        fw_size = dev_priv->csr.dmc_fw_size;
        for (i = 0; i < fw_size; i++)
                I915_WRITE(CSR_PROGRAM_BASE + i * 4,
-                       (u32 __force)payload[i]);
+                       payload[i]);
 
        for (i = 0; i < dev_priv->csr.mmio_count; i++) {
                I915_WRITE(dev_priv->csr.mmioaddr[i],
@@ -279,7 +279,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
        char substepping = intel_get_substepping(dev);
        uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes;
        uint32_t i;
-       __be32 *dmc_payload;
+       uint32_t *dmc_payload;
        bool fw_loaded = false;
 
        if (!fw) {
@@ -375,15 +375,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
        }
 
        dmc_payload = csr->dmc_payload;
-       for (i = 0; i < dmc_header->fw_size; i++) {
-               uint32_t *tmp = (u32 *)&fw->data[readcount + i * 4];
-               /*
-                * The firmware payload is an array of 32 bit words stored in
-                * little-endian format in the firmware image and programmed
-                * as 32 bit big-endian format to memory.
-                */
-               dmc_payload[i] = cpu_to_be32(*tmp);
-       }
+       memcpy(dmc_payload, &fw->data[readcount], nbytes);
 
        /* load csr program during system boot, as needed for DC states */
        intel_csr_load_program(dev);
index 9a40bfb20e0c8cabb62f425d68da7e7e1cea96bc..6cfe65d6a8cf96358f7858494d8232a2cc0b7ba6 100644 (file)
@@ -440,6 +440,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 reg;
+       u32 iboost_bit = 0;
        int i, n_hdmi_entries, n_dp_entries, n_edp_entries, hdmi_default_entry,
            size;
        int hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift;
@@ -466,6 +467,10 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
                ddi_translations_hdmi =
                                skl_get_buf_trans_hdmi(dev, &n_hdmi_entries);
                hdmi_default_entry = 8;
+               /* If we're boosting the current, set bit 31 of trans1 */
+               if (dev_priv->vbt.ddi_port_info[port].hdmi_boost_level ||
+                   dev_priv->vbt.ddi_port_info[port].dp_boost_level)
+                       iboost_bit = 1<<31;
        } else if (IS_BROADWELL(dev)) {
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
@@ -526,7 +531,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
        }
 
        for (i = 0, reg = DDI_BUF_TRANS(port); i < size; i++) {
-               I915_WRITE(reg, ddi_translations[i].trans1);
+               I915_WRITE(reg, ddi_translations[i].trans1 | iboost_bit);
                reg += 4;
                I915_WRITE(reg, ddi_translations[i].trans2);
                reg += 4;
@@ -541,7 +546,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
                hdmi_level = hdmi_default_entry;
 
        /* Entry 9 is for HDMI: */
-       I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans1);
+       I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans1 | iboost_bit);
        reg += 4;
        I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans2);
        reg += 4;
@@ -2078,18 +2083,35 @@ static void skl_ddi_set_iboost(struct drm_device *dev, u32 level,
        struct drm_i915_private *dev_priv = dev->dev_private;
        const struct ddi_buf_trans *ddi_translations;
        uint8_t iboost;
+       uint8_t dp_iboost, hdmi_iboost;
        int n_entries;
        u32 reg;
 
+       /* VBT may override standard boost values */
+       dp_iboost = dev_priv->vbt.ddi_port_info[port].dp_boost_level;
+       hdmi_iboost = dev_priv->vbt.ddi_port_info[port].hdmi_boost_level;
+
        if (type == INTEL_OUTPUT_DISPLAYPORT) {
-               ddi_translations = skl_get_buf_trans_dp(dev, &n_entries);
-               iboost = ddi_translations[port].i_boost;
+               if (dp_iboost) {
+                       iboost = dp_iboost;
+               } else {
+                       ddi_translations = skl_get_buf_trans_dp(dev, &n_entries);
+                       iboost = ddi_translations[port].i_boost;
+               }
        } else if (type == INTEL_OUTPUT_EDP) {
-               ddi_translations = skl_get_buf_trans_edp(dev, &n_entries);
-               iboost = ddi_translations[port].i_boost;
+               if (dp_iboost) {
+                       iboost = dp_iboost;
+               } else {
+                       ddi_translations = skl_get_buf_trans_edp(dev, &n_entries);
+                       iboost = ddi_translations[port].i_boost;
+               }
        } else if (type == INTEL_OUTPUT_HDMI) {
-               ddi_translations = skl_get_buf_trans_hdmi(dev, &n_entries);
-               iboost = ddi_translations[port].i_boost;
+               if (hdmi_iboost) {
+                       iboost = hdmi_iboost;
+               } else {
+                       ddi_translations = skl_get_buf_trans_hdmi(dev, &n_entries);
+                       iboost = ddi_translations[port].i_boost;
+               }
        } else {
                return;
        }
@@ -3184,10 +3206,9 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
                     dev_priv->vbt.ddi_port_info[port].supports_hdmi);
        init_dp = dev_priv->vbt.ddi_port_info[port].supports_dp;
        if (!init_dp && !init_hdmi) {
-               DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible, assuming it is\n",
+               DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible, respect it\n",
                              port_name(port));
-               init_hdmi = true;
-               init_dp = true;
+               return;
        }
 
        intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
index af0bcfee4771fd1af6ed0d2f06a5a9d4cf500f65..83936403502fb8a768783dbc5e24cf9f22035d61 100644 (file)
@@ -102,8 +102,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc,
                            const struct intel_crtc_state *pipe_config);
 static void chv_prepare_pll(struct intel_crtc *crtc,
                            const struct intel_crtc_state *pipe_config);
-static void intel_begin_crtc_commit(struct drm_crtc *crtc);
-static void intel_finish_crtc_commit(struct drm_crtc *crtc);
+static void intel_begin_crtc_commit(struct drm_crtc *, struct drm_crtc_state *);
+static void intel_finish_crtc_commit(struct drm_crtc *, struct drm_crtc_state *);
 static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_crtc,
        struct intel_crtc_state *crtc_state);
 static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
@@ -413,7 +413,7 @@ static const intel_limit_t intel_limits_bxt = {
 static bool
 needs_modeset(struct drm_crtc_state *state)
 {
-       return state->mode_changed || state->active_changed;
+       return drm_atomic_crtc_needs_modeset(state);
 }
 
 /**
@@ -1936,7 +1936,9 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc)
        struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
 
        /* PCH only available on ILK+ */
-       BUG_ON(INTEL_INFO(dev)->gen < 5);
+       if (INTEL_INFO(dev)->gen < 5)
+               return;
+
        if (pll == NULL)
                return;
 
@@ -2395,7 +2397,18 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
         * a fence as the cost is not that onerous.
         */
        ret = i915_gem_object_get_fence(obj);
-       if (ret)
+       if (ret == -EDEADLK) {
+               /*
+                * -EDEADLK means there are no free fences
+                * no pending flips.
+                *
+                * This is propagated to atomic, but it uses
+                * -EDEADLK to force a locking recovery, so
+                * change the returned error to -EBUSY.
+                */
+               ret = -EBUSY;
+               goto err_unpin;
+       } else if (ret)
                goto err_unpin;
 
        i915_gem_object_pin_fence(obj);
@@ -5134,6 +5147,7 @@ static enum intel_display_power_domain port_to_power_domain(enum port port)
 {
        switch (port) {
        case PORT_A:
+       case PORT_E:
                return POWER_DOMAIN_PORT_DDI_A_4_LANES;
        case PORT_B:
                return POWER_DOMAIN_PORT_DDI_B_4_LANES;
@@ -6271,67 +6285,6 @@ free:
        return ret;
 }
 
-/* Master function to enable/disable CRTC and corresponding power wells */
-int intel_crtc_control(struct drm_crtc *crtc, bool enable)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_mode_config *config = &dev->mode_config;
-       struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_crtc_state *pipe_config;
-       struct drm_atomic_state *state;
-       int ret;
-
-       if (enable == intel_crtc->active)
-               return 0;
-
-       if (enable && !crtc->state->enable)
-               return 0;
-
-       /* this function should be called with drm_modeset_lock_all for now */
-       if (WARN_ON(!ctx))
-               return -EIO;
-       lockdep_assert_held(&ctx->ww_ctx);
-
-       state = drm_atomic_state_alloc(dev);
-       if (WARN_ON(!state))
-               return -ENOMEM;
-
-       state->acquire_ctx = ctx;
-       state->allow_modeset = true;
-
-       pipe_config = intel_atomic_get_crtc_state(state, intel_crtc);
-       if (IS_ERR(pipe_config)) {
-               ret = PTR_ERR(pipe_config);
-               goto err;
-       }
-       pipe_config->base.active = enable;
-
-       ret = drm_atomic_commit(state);
-       if (!ret)
-               return ret;
-
-err:
-       DRM_ERROR("Updating crtc active failed with %i\n", ret);
-       drm_atomic_state_free(state);
-       return ret;
-}
-
-/**
- * Sets the power management mode of the pipe and plane.
- */
-void intel_crtc_update_dpms(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct intel_encoder *intel_encoder;
-       bool enable = false;
-
-       for_each_encoder_on_crtc(dev, crtc, intel_encoder)
-               enable |= intel_encoder->connectors_active;
-
-       intel_crtc_control(crtc, enable);
-}
-
 void intel_encoder_destroy(struct drm_encoder *encoder)
 {
        struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
@@ -6340,62 +6293,42 @@ void intel_encoder_destroy(struct drm_encoder *encoder)
        kfree(intel_encoder);
 }
 
-/* Simple dpms helper for encoders with just one connector, no cloning and only
- * one kind of off state. It clamps all !ON modes to fully OFF and changes the
- * state of the entire output pipe. */
-static void intel_encoder_dpms(struct intel_encoder *encoder, int mode)
-{
-       if (mode == DRM_MODE_DPMS_ON) {
-               encoder->connectors_active = true;
-
-               intel_crtc_update_dpms(encoder->base.crtc);
-       } else {
-               encoder->connectors_active = false;
-
-               intel_crtc_update_dpms(encoder->base.crtc);
-       }
-}
-
 /* Cross check the actual hw state with our own modeset state tracking (and it's
  * internal consistency). */
 static void intel_connector_check_state(struct intel_connector *connector)
 {
+       struct drm_crtc *crtc = connector->base.state->crtc;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.base.id,
+                     connector->base.name);
+
        if (connector->get_hw_state(connector)) {
-               struct intel_encoder *encoder = connector->encoder;
-               struct drm_crtc *crtc;
-               bool encoder_enabled;
-               enum pipe pipe;
+               struct drm_encoder *encoder = &connector->encoder->base;
+               struct drm_connector_state *conn_state = connector->base.state;
 
-               DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                             connector->base.base.id,
-                             connector->base.name);
+               I915_STATE_WARN(!crtc,
+                        "connector enabled without attached crtc\n");
 
-               /* there is no real hw state for MST connectors */
-               if (connector->mst_port)
+               if (!crtc)
                        return;
 
-               I915_STATE_WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
-                    "wrong connector dpms state\n");
-               I915_STATE_WARN(connector->base.encoder != &encoder->base,
-                    "active connector not linked to encoder\n");
+               I915_STATE_WARN(!crtc->state->active,
+                     "connector is active, but attached crtc isn't\n");
 
-               if (encoder) {
-                       I915_STATE_WARN(!encoder->connectors_active,
-                            "encoder->connectors_active not set\n");
-
-                       encoder_enabled = encoder->get_hw_state(encoder, &pipe);
-                       I915_STATE_WARN(!encoder_enabled, "encoder not enabled\n");
-                       if (I915_STATE_WARN_ON(!encoder->base.crtc))
-                               return;
+               if (!encoder)
+                       return;
 
-                       crtc = encoder->base.crtc;
+               I915_STATE_WARN(conn_state->best_encoder != encoder,
+                       "atomic encoder doesn't match attached encoder\n");
 
-                       I915_STATE_WARN(!crtc->state->enable,
-                                       "crtc not enabled\n");
-                       I915_STATE_WARN(!to_intel_crtc(crtc)->active, "crtc not active\n");
-                       I915_STATE_WARN(pipe != to_intel_crtc(crtc)->pipe,
-                            "encoder active on the wrong pipe\n");
-               }
+               I915_STATE_WARN(conn_state->crtc != encoder->crtc,
+                       "attached encoder crtc differs from connector crtc\n");
+       } else {
+               I915_STATE_WARN(crtc && crtc->state->active,
+                       "attached crtc is active, but connector isn't\n");
+               I915_STATE_WARN(!crtc && connector->base.state->best_encoder,
+                       "best encoder set without crtc!\n");
        }
 }
 
@@ -6427,26 +6360,6 @@ struct intel_connector *intel_connector_alloc(void)
        return connector;
 }
 
-/* Even simpler default implementation, if there's really no special case to
- * consider. */
-void intel_connector_dpms(struct drm_connector *connector, int mode)
-{
-       /* All the simple cases only support two dpms states. */
-       if (mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
-
-       if (mode == connector->dpms)
-               return;
-
-       connector->dpms = mode;
-
-       /* Only need to change hw state when actually enabled */
-       if (connector->encoder)
-               intel_encoder_dpms(to_intel_encoder(connector->encoder), mode);
-
-       intel_modeset_check_state(connector->dev);
-}
-
 /* Simple connector->get_hw_state implementation for encoders that support only
  * one connector and no cloning and hence the encoder state determines the state
  * of the connector. */
@@ -10219,7 +10132,7 @@ static struct drm_framebuffer *
 mode_fits_in_fbdev(struct drm_device *dev,
                   struct drm_display_mode *mode)
 {
-#ifdef CONFIG_DRM_I915_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
        struct drm_framebuffer *fb;
@@ -10762,15 +10675,12 @@ static void intel_unpin_work_fn(struct work_struct *__work)
                container_of(__work, struct intel_unpin_work, work);
        struct intel_crtc *crtc = to_intel_crtc(work->crtc);
        struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_plane *primary = crtc->base.primary;
 
        mutex_lock(&dev->struct_mutex);
        intel_unpin_fb_obj(work->old_fb, primary->state);
        drm_gem_object_unreference(&work->pending_flip_obj->base);
 
-       intel_fbc_update(dev_priv);
-
        if (work->flip_queued_req)
                i915_gem_request_assign(&work->flip_queued_req, NULL);
        mutex_unlock(&dev->struct_mutex);
@@ -11542,7 +11452,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                          to_intel_plane(primary)->frontbuffer_bit);
        mutex_unlock(&dev->struct_mutex);
 
-       intel_fbc_disable(dev_priv);
+       intel_fbc_disable_crtc(intel_crtc);
        intel_frontbuffer_flip_prepare(dev,
                                       to_intel_plane(primary)->frontbuffer_bit);
 
@@ -11838,7 +11748,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
        struct intel_crtc_state *pipe_config =
                to_intel_crtc_state(crtc_state);
        struct drm_atomic_state *state = crtc_state->state;
-       int ret, idx = crtc->base.id;
+       int ret;
        bool mode_changed = needs_modeset(crtc_state);
 
        if (mode_changed && !check_encoder_cloning(state, intel_crtc)) {
@@ -11846,10 +11756,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
-       I915_STATE_WARN(crtc->state->active != intel_crtc->active,
-               "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n",
-               idx, crtc->state->active, intel_crtc->active);
-
        if (mode_changed && !crtc_state->active)
                intel_crtc->atomic.update_wm_post = true;
 
@@ -12158,6 +12064,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        struct intel_dpll_hw_state dpll_hw_state;
        enum intel_dpll_id shared_dpll;
        uint32_t ddi_pll_sel;
+       bool force_thru;
 
        /* FIXME: before the switch to atomic started, a new pipe_config was
         * kzalloc'd. Code that depends on any field being zero should be
@@ -12169,6 +12076,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        shared_dpll = crtc_state->shared_dpll;
        dpll_hw_state = crtc_state->dpll_hw_state;
        ddi_pll_sel = crtc_state->ddi_pll_sel;
+       force_thru = crtc_state->pch_pfit.force_thru;
 
        memset(crtc_state, 0, sizeof *crtc_state);
 
@@ -12177,6 +12085,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        crtc_state->shared_dpll = shared_dpll;
        crtc_state->dpll_hw_state = dpll_hw_state;
        crtc_state->ddi_pll_sel = ddi_pll_sel;
+       crtc_state->pch_pfit.force_thru = force_thru;
 }
 
 static int
@@ -12278,7 +12187,9 @@ encoder_retry:
                goto encoder_retry;
        }
 
-       pipe_config->dither = pipe_config->pipe_bpp != base_bpp;
+       /* Dithering seems to not pass-through bits correctly when it should, so
+        * only enable it on 6bpc panels. */
+       pipe_config->dither = pipe_config->pipe_bpp == 6*3;
        DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n",
                      base_bpp, pipe_config->pipe_bpp, pipe_config->dither);
 
@@ -12286,48 +12197,15 @@ fail:
        return ret;
 }
 
-static bool intel_crtc_in_use(struct drm_crtc *crtc)
-{
-       struct drm_encoder *encoder;
-       struct drm_device *dev = crtc->dev;
-
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
-               if (encoder->crtc == crtc)
-                       return true;
-
-       return false;
-}
-
 static void
-intel_modeset_update_state(struct drm_atomic_state *state)
+intel_modeset_update_crtc_state(struct drm_atomic_state *state)
 {
-       struct drm_device *dev = state->dev;
-       struct intel_encoder *intel_encoder;
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
-       struct drm_connector *connector;
        int i;
 
-       intel_shared_dpll_commit(state);
-
-       for_each_intel_encoder(dev, intel_encoder) {
-               if (!intel_encoder->base.crtc)
-                       continue;
-
-               crtc = intel_encoder->base.crtc;
-               crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
-               if (!crtc_state || !needs_modeset(crtc->state))
-                       continue;
-
-               intel_encoder->connectors_active = false;
-       }
-
-       drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
-
        /* Double check state. */
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               WARN_ON(crtc->state->enable != intel_crtc_in_use(crtc));
-
                to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state);
 
                /* Update hwmode for vblank functions */
@@ -12336,28 +12214,6 @@ intel_modeset_update_state(struct drm_atomic_state *state)
                else
                        crtc->hwmode.crtc_clock = 0;
        }
-
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (!connector->encoder || !connector->encoder->crtc)
-                       continue;
-
-               crtc = connector->encoder->crtc;
-               crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
-               if (!crtc_state || !needs_modeset(crtc->state))
-                       continue;
-
-               if (crtc->state->active) {
-                       struct drm_property *dpms_property =
-                               dev->mode_config.dpms_property;
-
-                       connector->dpms = DRM_MODE_DPMS_ON;
-                       drm_object_property_set_value(&connector->base, dpms_property, DRM_MODE_DPMS_ON);
-
-                       intel_encoder = to_intel_encoder(connector->encoder);
-                       intel_encoder->connectors_active = true;
-               } else
-                       connector->dpms = DRM_MODE_DPMS_OFF;
-       }
 }
 
 static bool intel_fuzzy_clock_check(int clock1, int clock2)
@@ -12707,20 +12563,23 @@ static void check_wm_state(struct drm_device *dev)
 }
 
 static void
-check_connector_state(struct drm_device *dev)
+check_connector_state(struct drm_device *dev,
+                     struct drm_atomic_state *old_state)
 {
-       struct intel_connector *connector;
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector *connector;
+       int i;
 
-       for_each_intel_connector(dev, connector) {
-               struct drm_encoder *encoder = connector->base.encoder;
-               struct drm_connector_state *state = connector->base.state;
+       for_each_connector_in_state(old_state, connector, old_conn_state, i) {
+               struct drm_encoder *encoder = connector->encoder;
+               struct drm_connector_state *state = connector->state;
 
                /* This also checks the encoder/connector hw state with the
                 * ->get_hw_state callbacks. */
-               intel_connector_check_state(connector);
+               intel_connector_check_state(to_intel_connector(connector));
 
                I915_STATE_WARN(state->best_encoder != encoder,
-                    "connector's staged encoder doesn't match current encoder\n");
+                    "connector's atomic encoder doesn't match legacy encoder\n");
        }
 }
 
@@ -12732,133 +12591,106 @@ check_encoder_state(struct drm_device *dev)
 
        for_each_intel_encoder(dev, encoder) {
                bool enabled = false;
-               bool active = false;
-               enum pipe pipe, tracked_pipe;
+               enum pipe pipe;
 
                DRM_DEBUG_KMS("[ENCODER:%d:%s]\n",
                              encoder->base.base.id,
                              encoder->base.name);
 
-               I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc,
-                    "encoder's active_connectors set, but no crtc\n");
-
                for_each_intel_connector(dev, connector) {
-                       if (connector->base.encoder != &encoder->base)
+                       if (connector->base.state->best_encoder != &encoder->base)
                                continue;
                        enabled = true;
-                       if (connector->base.dpms != DRM_MODE_DPMS_OFF)
-                               active = true;
 
                        I915_STATE_WARN(connector->base.state->crtc !=
                                        encoder->base.crtc,
                             "connector's crtc doesn't match encoder crtc\n");
                }
-               /*
-                * for MST connectors if we unplug the connector is gone
-                * away but the encoder is still connected to a crtc
-                * until a modeset happens in response to the hotplug.
-                */
-               if (!enabled && encoder->base.encoder_type == DRM_MODE_ENCODER_DPMST)
-                       continue;
 
                I915_STATE_WARN(!!encoder->base.crtc != enabled,
                     "encoder's enabled state mismatch "
                     "(expected %i, found %i)\n",
                     !!encoder->base.crtc, enabled);
-               I915_STATE_WARN(active && !encoder->base.crtc,
-                    "active encoder with no crtc\n");
 
-               I915_STATE_WARN(encoder->connectors_active != active,
-                    "encoder's computed active state doesn't match tracked active state "
-                    "(expected %i, found %i)\n", active, encoder->connectors_active);
-
-               active = encoder->get_hw_state(encoder, &pipe);
-               I915_STATE_WARN(active != encoder->connectors_active,
-                    "encoder's hw state doesn't match sw tracking "
-                    "(expected %i, found %i)\n",
-                    encoder->connectors_active, active);
-
-               if (!encoder->base.crtc)
-                       continue;
-
-               tracked_pipe = to_intel_crtc(encoder->base.crtc)->pipe;
-               I915_STATE_WARN(active && pipe != tracked_pipe,
-                    "active encoder's pipe doesn't match"
-                    "(expected %i, found %i)\n",
-                    tracked_pipe, pipe);
+               if (!encoder->base.crtc) {
+                       bool active;
 
+                       active = encoder->get_hw_state(encoder, &pipe);
+                       I915_STATE_WARN(active,
+                            "encoder detached but still enabled on pipe %c.\n",
+                            pipe_name(pipe));
+               }
        }
 }
 
 static void
-check_crtc_state(struct drm_device *dev)
+check_crtc_state(struct drm_device *dev, struct drm_atomic_state *old_state)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *crtc;
        struct intel_encoder *encoder;
-       struct intel_crtc_state pipe_config;
+       struct drm_crtc_state *old_crtc_state;
+       struct drm_crtc *crtc;
+       int i;
 
-       for_each_intel_crtc(dev, crtc) {
-               bool enabled = false;
-               bool active = false;
+       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               struct intel_crtc_state *pipe_config, *sw_config;
+               bool active;
 
-               memset(&pipe_config, 0, sizeof(pipe_config));
+               if (!needs_modeset(crtc->state))
+                       continue;
 
-               DRM_DEBUG_KMS("[CRTC:%d]\n",
-                             crtc->base.base.id);
+               __drm_atomic_helper_crtc_destroy_state(crtc, old_crtc_state);
+               pipe_config = to_intel_crtc_state(old_crtc_state);
+               memset(pipe_config, 0, sizeof(*pipe_config));
+               pipe_config->base.crtc = crtc;
+               pipe_config->base.state = old_state;
 
-               I915_STATE_WARN(crtc->active && !crtc->base.state->enable,
-                    "active crtc, but not enabled in sw tracking\n");
+               DRM_DEBUG_KMS("[CRTC:%d]\n",
+                             crtc->base.id);
 
-               for_each_intel_encoder(dev, encoder) {
-                       if (encoder->base.crtc != &crtc->base)
-                               continue;
-                       enabled = true;
-                       if (encoder->connectors_active)
-                               active = true;
-               }
+               active = dev_priv->display.get_pipe_config(intel_crtc,
+                                                          pipe_config);
 
-               I915_STATE_WARN(active != crtc->active,
-                    "crtc's computed active state doesn't match tracked active state "
-                    "(expected %i, found %i)\n", active, crtc->active);
-               I915_STATE_WARN(enabled != crtc->base.state->enable,
-                    "crtc's computed enabled state doesn't match tracked enabled state "
-                    "(expected %i, found %i)\n", enabled,
-                               crtc->base.state->enable);
+               /* hw state is inconsistent with the pipe quirk */
+               if ((intel_crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
+                   (intel_crtc->pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
+                       active = crtc->state->active;
 
-               active = dev_priv->display.get_pipe_config(crtc,
-                                                          &pipe_config);
+               I915_STATE_WARN(crtc->state->active != active,
+                    "crtc active state doesn't match with hw state "
+                    "(expected %i, found %i)\n", crtc->state->active, active);
 
-               /* hw state is inconsistent with the pipe quirk */
-               if ((crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
-                   (crtc->pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
-                       active = crtc->active;
+               I915_STATE_WARN(intel_crtc->active != crtc->state->active,
+                    "transitional active state does not match atomic hw state "
+                    "(expected %i, found %i)\n", crtc->state->active, intel_crtc->active);
 
-               for_each_intel_encoder(dev, encoder) {
+               for_each_encoder_on_crtc(dev, crtc, encoder) {
                        enum pipe pipe;
-                       if (encoder->base.crtc != &crtc->base)
-                               continue;
-                       if (encoder->get_hw_state(encoder, &pipe))
-                               encoder->get_config(encoder, &pipe_config);
-               }
 
-               I915_STATE_WARN(crtc->active != active,
-                    "crtc active state doesn't match with hw state "
-                    "(expected %i, found %i)\n", crtc->active, active);
+                       active = encoder->get_hw_state(encoder, &pipe);
+                       I915_STATE_WARN(active != crtc->state->active,
+                               "[ENCODER:%i] active %i with crtc active %i\n",
+                               encoder->base.base.id, active, crtc->state->active);
 
-               I915_STATE_WARN(crtc->active != crtc->base.state->active,
-                    "transitional active state does not match atomic hw state "
-                    "(expected %i, found %i)\n", crtc->base.state->active, crtc->active);
+                       I915_STATE_WARN(active && intel_crtc->pipe != pipe,
+                                       "Encoder connected to wrong pipe %c\n",
+                                       pipe_name(pipe));
 
-               if (!active)
+                       if (active)
+                               encoder->get_config(encoder, pipe_config);
+               }
+
+               if (!crtc->state->active)
                        continue;
 
-               if (!intel_pipe_config_compare(dev, crtc->config,
-                                              &pipe_config, false)) {
+               sw_config = to_intel_crtc_state(crtc->state);
+               if (!intel_pipe_config_compare(dev, sw_config,
+                                              pipe_config, false)) {
                        I915_STATE_WARN(1, "pipe state doesn't match!\n");
-                       intel_dump_pipe_config(crtc, &pipe_config,
+                       intel_dump_pipe_config(intel_crtc, pipe_config,
                                               "[hw state]");
-                       intel_dump_pipe_config(crtc, crtc->config,
+                       intel_dump_pipe_config(intel_crtc, sw_config,
                                               "[sw state]");
                }
        }
@@ -12913,13 +12745,14 @@ check_shared_dpll_state(struct drm_device *dev)
        }
 }
 
-void
-intel_modeset_check_state(struct drm_device *dev)
+static void
+intel_modeset_check_state(struct drm_device *dev,
+                         struct drm_atomic_state *old_state)
 {
        check_wm_state(dev);
-       check_connector_state(dev);
+       check_connector_state(dev, old_state);
        check_encoder_state(dev);
-       check_crtc_state(dev);
+       check_crtc_state(dev, old_state);
        check_shared_dpll_state(dev);
 }
 
@@ -13275,12 +13108,14 @@ static int intel_atomic_commit(struct drm_device *dev,
 
        /* Only after disabling all output pipelines that will be changed can we
         * update the the output configuration. */
-       intel_modeset_update_state(state);
+       intel_modeset_update_crtc_state(state);
 
-       /* The state has been swaped above, so state actually contains the
-        * old state now. */
-       if (any_ms)
+       if (any_ms) {
+               intel_shared_dpll_commit(state);
+
+               drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
                modeset_update_crtc_power_domains(state);
+       }
 
        /* Now enable the clocks, plane, pipe, and connectors that we set up. */
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
@@ -13303,10 +13138,11 @@ static int intel_atomic_commit(struct drm_device *dev,
 
        drm_atomic_helper_wait_for_vblanks(dev, state);
        drm_atomic_helper_cleanup_planes(dev, state);
-       drm_atomic_state_free(state);
 
        if (any_ms)
-               intel_modeset_check_state(dev);
+               intel_modeset_check_state(dev, state);
+
+       drm_atomic_state_free(state);
 
        return 0;
 }
@@ -13628,7 +13464,8 @@ intel_disable_primary_plane(struct drm_plane *plane,
        dev_priv->display.update_primary_plane(crtc, NULL, 0, 0);
 }
 
-static void intel_begin_crtc_commit(struct drm_crtc *crtc)
+static void intel_begin_crtc_commit(struct drm_crtc *crtc,
+                                   struct drm_crtc_state *old_crtc_state)
 {
        struct drm_device *dev = crtc->dev;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -13644,7 +13481,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc)
                skl_detach_scalers(intel_crtc);
 }
 
-static void intel_finish_crtc_commit(struct drm_crtc *crtc)
+static void intel_finish_crtc_commit(struct drm_crtc *crtc,
+                                    struct drm_crtc_state *old_crtc_state)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
@@ -13684,7 +13522,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
        struct intel_plane *primary;
        struct intel_plane_state *state;
        const uint32_t *intel_primary_formats;
-       int num_formats;
+       unsigned int num_formats;
 
        primary = kzalloc(sizeof(*primary), GFP_KERNEL);
        if (primary == NULL)
@@ -14109,8 +13947,7 @@ static void intel_setup_outputs(struct drm_device *dev)
                 */
                found = I915_READ(DDI_BUF_CTL_A) & DDI_INIT_DISPLAY_DETECTED;
                /* WaIgnoreDDIAStrap: skl */
-               if (found ||
-                   (IS_SKYLAKE(dev) && INTEL_REVID(dev) < SKL_REVID_D0))
+               if (found || IS_SKYLAKE(dev))
                        intel_ddi_init(dev, PORT_A);
 
                /* DDI B, C and D detection is indicated by the SFUSE_STRAP
@@ -14274,7 +14111,7 @@ static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb,
        struct drm_i915_gem_object *obj = intel_fb->obj;
 
        mutex_lock(&dev->struct_mutex);
-       intel_fb_obj_flush(obj, false, ORIGIN_GTT);
+       intel_fb_obj_flush(obj, false, ORIGIN_DIRTYFB);
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -14478,7 +14315,7 @@ intel_user_framebuffer_create(struct drm_device *dev,
        return intel_framebuffer_create(dev, mode_cmd, obj);
 }
 
-#ifndef CONFIG_DRM_I915_FBDEV
+#ifndef CONFIG_DRM_FBDEV_EMULATION
 static inline void intel_fbdev_output_poll_changed(struct drm_device *dev)
 {
 }
@@ -15068,8 +14905,10 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
        /* Adjust the state of the output pipe according to whether we
         * have active connectors/encoders. */
        enable = false;
-       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
-               enable |= encoder->connectors_active;
+       for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
+               enable = true;
+               break;
+       }
 
        if (!enable)
                intel_crtc_disable_noatomic(&crtc->base);
@@ -15096,10 +14935,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                 *  actually up, hence no need to break them. */
                WARN_ON(crtc->active);
 
-               for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
-                       WARN_ON(encoder->connectors_active);
+               for_each_encoder_on_crtc(dev, &crtc->base, encoder)
                        encoder->base.crtc = NULL;
-               }
        }
 
        if (crtc->active || HAS_GMCH_DISPLAY(dev)) {
@@ -15125,6 +14962,7 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
 {
        struct intel_connector *connector;
        struct drm_device *dev = encoder->base.dev;
+       bool active = false;
 
        /* We need to check both for a crtc link (meaning that the
         * encoder is active and trying to read from a pipe) and the
@@ -15132,7 +14970,15 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
        bool has_active_crtc = encoder->base.crtc &&
                to_intel_crtc(encoder->base.crtc)->active;
 
-       if (encoder->connectors_active && !has_active_crtc) {
+       for_each_intel_connector(dev, connector) {
+               if (connector->base.encoder != &encoder->base)
+                       continue;
+
+               active = true;
+               break;
+       }
+
+       if (active && !has_active_crtc) {
                DRM_DEBUG_KMS("[ENCODER:%d:%s] has active connectors but no active pipe!\n",
                              encoder->base.base.id,
                              encoder->base.name);
@@ -15149,7 +14995,6 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
                                encoder->post_disable(encoder);
                }
                encoder->base.crtc = NULL;
-               encoder->connectors_active = false;
 
                /* Inconsistent output/port/pipe state happens presumably due to
                 * a bug in one of the get_hw_state functions. Or someplace else
@@ -15311,7 +15156,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                        encoder->base.crtc = NULL;
                }
 
-               encoder->connectors_active = false;
                DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe %c\n",
                              encoder->base.base.id,
                              encoder->base.name,
@@ -15322,7 +15166,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
        for_each_intel_connector(dev, connector) {
                if (connector->get_hw_state(connector)) {
                        connector->base.dpms = DRM_MODE_DPMS_ON;
-                       connector->encoder->connectors_active = true;
                        connector->base.encoder = &connector->encoder->base;
                } else {
                        connector->base.dpms = DRM_MODE_DPMS_OFF;
index f1b9f939b4352b31d00b85b46373cc0b51169acc..016e7bc6af0abe33dcec4dd5d37b04420a042a0f 100644 (file)
@@ -849,8 +849,15 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        }
 
        if (try == 3) {
-               WARN(1, "dp_aux_ch not started status 0x%08x\n",
-                    I915_READ(ch_ctl));
+               static u32 last_status = -1;
+               const u32 status = I915_READ(ch_ctl);
+
+               if (status != last_status) {
+                       WARN(1, "dp_aux_ch not started status 0x%08x\n",
+                            status);
+                       last_status = status;
+               }
+
                ret = -EBUSY;
                goto out;
        }
@@ -1026,11 +1033,34 @@ static void
 intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        enum port port = intel_dig_port->port;
+       struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port];
        const char *name = NULL;
+       uint32_t porte_aux_ctl_reg = DPA_AUX_CH_CTL;
        int ret;
 
+       /* On SKL we don't have Aux for port E so we rely on VBT to set
+        * a proper alternate aux channel.
+        */
+       if (IS_SKYLAKE(dev) && port == PORT_E) {
+               switch (info->alternate_aux_channel) {
+               case DP_AUX_B:
+                       porte_aux_ctl_reg = DPB_AUX_CH_CTL;
+                       break;
+               case DP_AUX_C:
+                       porte_aux_ctl_reg = DPC_AUX_CH_CTL;
+                       break;
+               case DP_AUX_D:
+                       porte_aux_ctl_reg = DPD_AUX_CH_CTL;
+                       break;
+               case DP_AUX_A:
+               default:
+                       porte_aux_ctl_reg = DPA_AUX_CH_CTL;
+               }
+       }
+
        switch (port) {
        case PORT_A:
                intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL;
@@ -1048,6 +1078,10 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
                intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL;
                name = "DPDDC-D";
                break;
+       case PORT_E:
+               intel_dp->aux_ch_ctl_reg = porte_aux_ctl_reg;
+               name = "DPDDC-E";
+               break;
        default:
                BUG();
        }
@@ -1061,7 +1095,7 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
         *
         * Skylake moves AUX_CTL back next to DDI_BUF_CTL, on the CPU.
         */
-       if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
+       if (!IS_HASWELL(dev) && !IS_BROADWELL(dev) && port != PORT_E)
                intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10;
 
        intel_dp->aux.name = name;
@@ -1409,7 +1443,10 @@ intel_dp_compute_config(struct intel_encoder *encoder,
         * bpc in between. */
        bpp = pipe_config->pipe_bpp;
        if (is_edp(intel_dp)) {
-               if (dev_priv->vbt.edp_bpp && dev_priv->vbt.edp_bpp < bpp) {
+
+               /* Get bpp from vbt only for panels that dont have bpp in edid */
+               if (intel_connector->base.display_info.bpc == 0 &&
+                       (dev_priv->vbt.edp_bpp && dev_priv->vbt.edp_bpp < bpp)) {
                        DRM_DEBUG_KMS("clamping bpp for eDP panel to BIOS-provided %i\n",
                                      dev_priv->vbt.edp_bpp);
                        bpp = dev_priv->vbt.edp_bpp;
@@ -2624,7 +2661,7 @@ static void vlv_steal_power_sequencer(struct drm_device *dev,
                DRM_DEBUG_KMS("stealing pipe %c power sequencer from port %c\n",
                              pipe_name(pipe), port_name(port));
 
-               WARN(encoder->connectors_active,
+               WARN(encoder->base.crtc,
                     "stealing pipe %c power sequencer from active eDP port %c\n",
                     pipe_name(pipe), port_name(port));
 
@@ -3958,43 +3995,67 @@ intel_dp_probe_mst(struct intel_dp *intel_dp)
        return intel_dp->is_mst;
 }
 
-int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
+static void intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
 {
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_device *dev = intel_dig_port->base.base.dev;
-       struct intel_crtc *intel_crtc =
-               to_intel_crtc(intel_dig_port->base.base.crtc);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
        u8 buf;
-       int test_crc_count;
-       int attempts = 6;
-       int ret = 0;
 
-       hsw_disable_ips(intel_crtc);
-
-       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) {
-               ret = -EIO;
-               goto out;
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) {
+               DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n");
+               return;
        }
 
-       if (!(buf & DP_TEST_CRC_SUPPORTED)) {
-               ret = -ENOTTY;
-               goto out;
-       }
+       if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
+                              buf & ~DP_TEST_SINK_START) < 0)
+               DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n");
 
-       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) {
-               ret = -EIO;
-               goto out;
-       }
+       hsw_enable_ips(intel_crtc);
+}
+
+static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
+       u8 buf;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0)
+               return -EIO;
+
+       if (!(buf & DP_TEST_CRC_SUPPORTED))
+               return -ENOTTY;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0)
+               return -EIO;
+
+       hsw_disable_ips(intel_crtc);
 
        if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
-                               buf | DP_TEST_SINK_START) < 0) {
-               ret = -EIO;
-               goto out;
+                              buf | DP_TEST_SINK_START) < 0) {
+               hsw_enable_ips(intel_crtc);
+               return -EIO;
        }
 
+       return 0;
+}
+
+int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
+{
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = dig_port->base.base.dev;
+       struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
+       u8 buf;
+       int test_crc_count;
+       int attempts = 6;
+       int ret;
+
+       ret = intel_dp_sink_crc_start(intel_dp);
+       if (ret)
+               return ret;
+
        if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) {
                ret = -EIO;
-               goto out;
+               goto stop;
        }
 
        test_crc_count = buf & DP_TEST_COUNT_MASK;
@@ -4003,7 +4064,7 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
                if (drm_dp_dpcd_readb(&intel_dp->aux,
                                      DP_TEST_SINK_MISC, &buf) < 0) {
                        ret = -EIO;
-                       goto out;
+                       goto stop;
                }
                intel_wait_for_vblank(dev, intel_crtc->pipe);
        } while (--attempts && (buf & DP_TEST_COUNT_MASK) == test_crc_count);
@@ -4011,25 +4072,13 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
        if (attempts == 0) {
                DRM_DEBUG_KMS("Panel is unable to calculate CRC after 6 vblanks\n");
                ret = -ETIMEDOUT;
-               goto out;
-       }
-
-       if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) {
-               ret = -EIO;
-               goto out;
+               goto stop;
        }
 
-       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) {
-               ret = -EIO;
-               goto out;
-       }
-       if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
-                              buf & ~DP_TEST_SINK_START) < 0) {
+       if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0)
                ret = -EIO;
-               goto out;
-       }
-out:
-       hsw_enable_ips(intel_crtc);
+stop:
+       intel_dp_sink_crc_stop(intel_dp);
        return ret;
 }
 
@@ -4090,9 +4139,16 @@ static uint8_t intel_dp_autotest_edid(struct intel_dp *intel_dp)
                                      intel_dp->aux.i2c_defer_count);
                intel_dp->compliance_test_data = INTEL_DP_RESOLUTION_FAILSAFE;
        } else {
+               struct edid *block = intel_connector->detect_edid;
+
+               /* We have to write the checksum
+                * of the last block read
+                */
+               block += intel_connector->detect_edid->extensions;
+
                if (!drm_dp_dpcd_write(&intel_dp->aux,
                                        DP_TEST_EDID_CHECKSUM,
-                                       &intel_connector->detect_edid->checksum,
+                                       &block->checksum,
                                        1))
                        DRM_DEBUG_KMS("Failed to write EDID checksum\n");
 
@@ -4240,10 +4296,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
 
        WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
 
-       if (!intel_encoder->connectors_active)
-               return;
-
-       if (WARN_ON(!intel_encoder->base.crtc))
+       if (!intel_encoder->base.crtc)
                return;
 
        if (!to_intel_crtc(intel_encoder->base.crtc)->active)
@@ -4824,7 +4877,7 @@ static void intel_dp_encoder_reset(struct drm_encoder *encoder)
 }
 
 static const struct drm_connector_funcs intel_dp_connector_funcs = {
-       .dpms = intel_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .detect = intel_dp_detect,
        .force = intel_dp_force,
        .fill_modes = drm_helper_probe_single_connector_modes,
index 585f0a45b3f1cf0cb53603c9204f9c271eb06df1..369f8b6b804fe23381cee2146cd8e289fba8c526 100644 (file)
@@ -328,7 +328,7 @@ intel_dp_mst_connector_destroy(struct drm_connector *connector)
 }
 
 static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
-       .dpms = intel_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .detect = intel_dp_mst_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_dp_mst_set_property,
@@ -357,6 +357,16 @@ intel_dp_mst_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
+static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector,
+                                                        struct drm_connector_state *state)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_dp *intel_dp = intel_connector->mst_port;
+       struct intel_crtc *crtc = to_intel_crtc(state->crtc);
+
+       return &intel_dp->mst_encoders[crtc->pipe]->base.base;
+}
+
 static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector)
 {
        struct intel_connector *intel_connector = to_intel_connector(connector);
@@ -367,6 +377,7 @@ static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connecto
 static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
        .get_modes = intel_dp_mst_get_modes,
        .mode_valid = intel_dp_mst_mode_valid,
+       .atomic_best_encoder = intel_mst_atomic_best_encoder,
        .best_encoder = intel_mst_best_encoder,
 };
 
@@ -395,7 +406,7 @@ static bool intel_dp_mst_get_hw_state(struct intel_connector *connector)
 
 static void intel_connector_add_to_fbdev(struct intel_connector *connector)
 {
-#ifdef CONFIG_DRM_I915_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
        drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, &connector->base);
 #endif
@@ -403,7 +414,7 @@ static void intel_connector_add_to_fbdev(struct intel_connector *connector)
 
 static void intel_connector_remove_from_fbdev(struct intel_connector *connector)
 {
-#ifdef CONFIG_DRM_I915_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
        drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, &connector->base);
 #endif
@@ -453,9 +464,20 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
 {
        struct intel_connector *intel_connector = to_intel_connector(connector);
        struct drm_device *dev = connector->dev;
+
        /* need to nuke the connector */
        drm_modeset_lock_all(dev);
-       intel_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+       if (connector->state->crtc) {
+               struct drm_mode_set set;
+               int ret;
+
+               memset(&set, 0, sizeof(set));
+               set.crtc = connector->state->crtc,
+
+               ret = drm_atomic_helper_set_config(&set);
+
+               WARN(ret, "Disabling mst crtc failed with %i\n", ret);
+       }
        drm_modeset_unlock_all(dev);
 
        intel_connector->unregister(intel_connector);
index 47cef0e6c79c985c3e1930ac02beb9eccac08d46..93008fbb815d93012d7b5dbcdfd52b0bbfa10af0 100644 (file)
@@ -133,7 +133,6 @@ struct intel_encoder {
 
        enum intel_output_type type;
        unsigned int cloneable;
-       bool connectors_active;
        void (*hot_plug)(struct intel_encoder *);
        bool (*compute_config)(struct intel_encoder *,
                               struct intel_crtc_state *);
@@ -992,14 +991,10 @@ void intel_mark_busy(struct drm_device *dev);
 void intel_mark_idle(struct drm_device *dev);
 void intel_crtc_restore_mode(struct drm_crtc *crtc);
 int intel_display_suspend(struct drm_device *dev);
-int intel_crtc_control(struct drm_crtc *crtc, bool enable);
-void intel_crtc_update_dpms(struct drm_crtc *crtc);
 void intel_encoder_destroy(struct drm_encoder *encoder);
 int intel_connector_init(struct intel_connector *);
 struct intel_connector *intel_connector_alloc(void);
-void intel_connector_dpms(struct drm_connector *, int mode);
 bool intel_connector_get_hw_state(struct intel_connector *connector);
-void intel_modeset_check_state(struct drm_device *dev);
 bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
                                struct intel_digital_port *port);
 void intel_connector_attach_encoder(struct intel_connector *connector,
@@ -1203,7 +1198,7 @@ void intel_dvo_init(struct drm_device *dev);
 
 
 /* legacy fbdev emulation in intel_fbdev.c */
-#ifdef CONFIG_DRM_I915_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 extern int intel_fbdev_init(struct drm_device *dev);
 extern void intel_fbdev_initial_config(void *data, async_cookie_t cookie);
 extern void intel_fbdev_fini(struct drm_device *dev);
@@ -1243,7 +1238,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
                          unsigned int frontbuffer_bits,
                          enum fb_op_origin origin);
 void intel_fbc_flush(struct drm_i915_private *dev_priv,
-                    unsigned int frontbuffer_bits);
+                    unsigned int frontbuffer_bits, enum fb_op_origin origin);
 const char *intel_no_fbc_reason_str(enum no_fbc_reason reason);
 void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv);
 
index 18dd7d7360a06e58e65fb632fb7d275cc1fb05fb..4a601cf90f16c68d694babd065bbae09cbe6e9f7 100644 (file)
@@ -982,7 +982,7 @@ static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs
 };
 
 static const struct drm_connector_funcs intel_dsi_connector_funcs = {
-       .dpms = intel_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .detect = intel_dsi_detect,
        .destroy = intel_dsi_connector_destroy,
        .fill_modes = drm_helper_probe_single_connector_modes,
index ece5bd754f85f5c0de25de036ba232ca19986b32..dc532bb61d229834dafeaf7d3ba54f50042763ea 100644 (file)
@@ -196,50 +196,6 @@ static void intel_enable_dvo(struct intel_encoder *encoder)
        intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
 }
 
-/* Special dpms function to support cloning between dvo/sdvo/crt. */
-static void intel_dvo_dpms(struct drm_connector *connector, int mode)
-{
-       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
-       struct drm_crtc *crtc;
-       struct intel_crtc_state *config;
-
-       /* dvo supports only 2 dpms states. */
-       if (mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
-
-       if (mode == connector->dpms)
-               return;
-
-       connector->dpms = mode;
-
-       /* Only need to change hw state when actually enabled */
-       crtc = intel_dvo->base.base.crtc;
-       if (!crtc) {
-               intel_dvo->base.connectors_active = false;
-               return;
-       }
-
-       /* We call connector dpms manually below in case pipe dpms doesn't
-        * change due to cloning. */
-       if (mode == DRM_MODE_DPMS_ON) {
-               config = to_intel_crtc(crtc)->config;
-
-               intel_dvo->base.connectors_active = true;
-
-               intel_crtc_update_dpms(crtc);
-
-               intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
-       } else {
-               intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
-
-               intel_dvo->base.connectors_active = false;
-
-               intel_crtc_update_dpms(crtc);
-       }
-
-       intel_modeset_check_state(connector->dev);
-}
-
 static enum drm_mode_status
 intel_dvo_mode_valid(struct drm_connector *connector,
                     struct drm_display_mode *mode)
@@ -387,7 +343,7 @@ static void intel_dvo_destroy(struct drm_connector *connector)
 }
 
 static const struct drm_connector_funcs intel_dvo_connector_funcs = {
-       .dpms = intel_dvo_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .detect = intel_dvo_detect,
        .destroy = intel_dvo_destroy,
        .fill_modes = drm_helper_probe_single_connector_modes,
index c271af7679815bedee3623efc869b15de1b551b2..1f97fb548c2ac6b937e2b5e8f0a7a29c9592a9b2 100644 (file)
@@ -884,22 +884,23 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
 }
 
 void intel_fbc_flush(struct drm_i915_private *dev_priv,
-                    unsigned int frontbuffer_bits)
+                    unsigned int frontbuffer_bits, enum fb_op_origin origin)
 {
        if (!dev_priv->fbc.enable_fbc)
                return;
 
-       mutex_lock(&dev_priv->fbc.lock);
+       if (origin == ORIGIN_GTT)
+               return;
 
-       if (!dev_priv->fbc.busy_bits)
-               goto out;
+       mutex_lock(&dev_priv->fbc.lock);
 
        dev_priv->fbc.busy_bits &= ~frontbuffer_bits;
 
-       if (!dev_priv->fbc.busy_bits)
+       if (!dev_priv->fbc.busy_bits) {
+               __intel_fbc_disable(dev_priv);
                __intel_fbc_update(dev_priv);
+       }
 
-out:
        mutex_unlock(&dev_priv->fbc.lock);
 }
 
index 7eff33ff84f69de52839817ac8d57ac219da5b53..8c6a6fa460057d38c71fe8f01986cde39f234442 100644 (file)
@@ -55,13 +55,6 @@ static int intel_fbdev_set_par(struct fb_info *info)
        ret = drm_fb_helper_set_par(info);
 
        if (ret == 0) {
-               /*
-                * FIXME: fbdev presumes that all callbacks also work from
-                * atomic contexts and relies on that for emergency oops
-                * printing. KMS totally doesn't do that and the locking here is
-                * by far not the only place this goes wrong.  Ignore this for
-                * now until we solve this for real.
-                */
                mutex_lock(&fb_helper->dev->struct_mutex);
                intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
                mutex_unlock(&fb_helper->dev->struct_mutex);
@@ -80,13 +73,6 @@ static int intel_fbdev_blank(int blank, struct fb_info *info)
        ret = drm_fb_helper_blank(blank, info);
 
        if (ret == 0) {
-               /*
-                * FIXME: fbdev presumes that all callbacks also work from
-                * atomic contexts and relies on that for emergency oops
-                * printing. KMS totally doesn't do that and the locking here is
-                * by far not the only place this goes wrong.  Ignore this for
-                * now until we solve this for real.
-                */
                mutex_lock(&fb_helper->dev->struct_mutex);
                intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
                mutex_unlock(&fb_helper->dev->struct_mutex);
@@ -106,13 +92,6 @@ static int intel_fbdev_pan_display(struct fb_var_screeninfo *var,
        ret = drm_fb_helper_pan_display(var, info);
 
        if (ret == 0) {
-               /*
-                * FIXME: fbdev presumes that all callbacks also work from
-                * atomic contexts and relies on that for emergency oops
-                * printing. KMS totally doesn't do that and the locking here is
-                * by far not the only place this goes wrong.  Ignore this for
-                * now until we solve this for real.
-                */
                mutex_lock(&fb_helper->dev->struct_mutex);
                intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
                mutex_unlock(&fb_helper->dev->struct_mutex);
@@ -125,9 +104,9 @@ static struct fb_ops intelfb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = intel_fbdev_set_par,
-       .fb_fillrect = cfb_fillrect,
-       .fb_copyarea = cfb_copyarea,
-       .fb_imageblit = cfb_imageblit,
+       .fb_fillrect = drm_fb_helper_cfb_fillrect,
+       .fb_copyarea = drm_fb_helper_cfb_copyarea,
+       .fb_imageblit = drm_fb_helper_cfb_imageblit,
        .fb_pan_display = intel_fbdev_pan_display,
        .fb_blank = intel_fbdev_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
@@ -236,9 +215,9 @@ static int intelfb_create(struct drm_fb_helper *helper,
        obj = intel_fb->obj;
        size = obj->base.size;
 
-       info = framebuffer_alloc(0, &dev->pdev->dev);
-       if (!info) {
-               ret = -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info)) {
+               ret = PTR_ERR(info);
                goto out_unpin;
        }
 
@@ -247,24 +226,13 @@ static int intelfb_create(struct drm_fb_helper *helper,
        fb = &ifbdev->fb->base;
 
        ifbdev->helper.fb = fb;
-       ifbdev->helper.fbdev = info;
 
        strcpy(info->fix.id, "inteldrmfb");
 
        info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
        info->fbops = &intelfb_ops;
 
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto out_unpin;
-       }
        /* setup aperture base/size for vesafb takeover */
-       info->apertures = alloc_apertures(1);
-       if (!info->apertures) {
-               ret = -ENOMEM;
-               goto out_unpin;
-       }
        info->apertures->ranges[0].base = dev->mode_config.fb_base;
        info->apertures->ranges[0].size = dev_priv->gtt.mappable_end;
 
@@ -276,7 +244,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
                           size);
        if (!info->screen_base) {
                ret = -ENOSPC;
-               goto out_unpin;
+               goto out_destroy_fbi;
        }
        info->screen_size = size;
 
@@ -303,6 +271,8 @@ static int intelfb_create(struct drm_fb_helper *helper,
        vga_switcheroo_client_fb_set(dev->pdev, info);
        return 0;
 
+out_destroy_fbi:
+       drm_fb_helper_release_fbi(helper);
 out_unpin:
        i915_gem_object_ggtt_unpin(obj);
        drm_gem_object_unreference(&obj->base);
@@ -544,16 +514,9 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
 static void intel_fbdev_destroy(struct drm_device *dev,
                                struct intel_fbdev *ifbdev)
 {
-       if (ifbdev->helper.fbdev) {
-               struct fb_info *info = ifbdev->helper.fbdev;
 
-               unregister_framebuffer(info);
-               iounmap(info->screen_base);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&ifbdev->helper);
+       drm_fb_helper_release_fbi(&ifbdev->helper);
 
        drm_fb_helper_fini(&ifbdev->helper);
 
@@ -802,7 +765,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous
        if (state == FBINFO_STATE_RUNNING && ifbdev->fb->obj->stolen)
                memset_io(info->screen_base, 0, info->screen_size);
 
-       fb_set_suspend(info, state);
+       drm_fb_helper_set_suspend(&ifbdev->helper, state);
        console_unlock();
 }
 
index 777b1d3ccd41992bacad8c75a18a0c9ec5f398a4..ac85357010b4b652ec15811d9c7d4a3b52ad8ebd 100644 (file)
@@ -129,7 +129,7 @@ static void intel_frontbuffer_flush(struct drm_device *dev,
 
        intel_edp_drrs_flush(dev, frontbuffer_bits);
        intel_psr_flush(dev, frontbuffer_bits, origin);
-       intel_fbc_flush(dev_priv, frontbuffer_bits);
+       intel_fbc_flush(dev_priv, frontbuffer_bits, origin);
 }
 
 /**
diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
new file mode 100644 (file)
index 0000000..18d7f20
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright Â© 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef _INTEL_GUC_FWIF_H
+#define _INTEL_GUC_FWIF_H
+
+/*
+ * This file is partially autogenerated, although currently with some manual
+ * fixups afterwards. In future, it should be entirely autogenerated, in order
+ * to ensure that the definitions herein remain in sync with those used by the
+ * GuC's own firmware.
+ *
+ * EDITING THIS FILE IS THEREFORE NOT RECOMMENDED - YOUR CHANGES MAY BE LOST.
+ */
+
+#define GFXCORE_FAMILY_GEN8            11
+#define GFXCORE_FAMILY_GEN9            12
+#define GFXCORE_FAMILY_FORCE_ULONG     0x7fffffff
+
+#define GUC_CTX_PRIORITY_CRITICAL      0
+#define GUC_CTX_PRIORITY_HIGH          1
+#define GUC_CTX_PRIORITY_NORMAL                2
+#define GUC_CTX_PRIORITY_LOW           3
+
+#define GUC_MAX_GPU_CONTEXTS           1024
+#define        GUC_INVALID_CTX_ID              (GUC_MAX_GPU_CONTEXTS + 1)
+
+/* Work queue item header definitions */
+#define WQ_STATUS_ACTIVE               1
+#define WQ_STATUS_SUSPENDED            2
+#define WQ_STATUS_CMD_ERROR            3
+#define WQ_STATUS_ENGINE_ID_NOT_USED   4
+#define WQ_STATUS_SUSPENDED_FROM_RESET 5
+#define WQ_TYPE_SHIFT                  0
+#define   WQ_TYPE_BATCH_BUF            (0x1 << WQ_TYPE_SHIFT)
+#define   WQ_TYPE_PSEUDO               (0x2 << WQ_TYPE_SHIFT)
+#define   WQ_TYPE_INORDER              (0x3 << WQ_TYPE_SHIFT)
+#define WQ_TARGET_SHIFT                        10
+#define WQ_LEN_SHIFT                   16
+#define WQ_NO_WCFLUSH_WAIT             (1 << 27)
+#define WQ_PRESENT_WORKLOAD            (1 << 28)
+#define WQ_WORKLOAD_SHIFT              29
+#define   WQ_WORKLOAD_GENERAL          (0 << WQ_WORKLOAD_SHIFT)
+#define   WQ_WORKLOAD_GPGPU            (1 << WQ_WORKLOAD_SHIFT)
+#define   WQ_WORKLOAD_TOUCH            (2 << WQ_WORKLOAD_SHIFT)
+
+#define WQ_RING_TAIL_SHIFT             20
+#define WQ_RING_TAIL_MASK              (0x7FF << WQ_RING_TAIL_SHIFT)
+
+#define GUC_DOORBELL_ENABLED           1
+#define GUC_DOORBELL_DISABLED          0
+
+#define GUC_CTX_DESC_ATTR_ACTIVE       (1 << 0)
+#define GUC_CTX_DESC_ATTR_PENDING_DB   (1 << 1)
+#define GUC_CTX_DESC_ATTR_KERNEL       (1 << 2)
+#define GUC_CTX_DESC_ATTR_PREEMPT      (1 << 3)
+#define GUC_CTX_DESC_ATTR_RESET                (1 << 4)
+#define GUC_CTX_DESC_ATTR_WQLOCKED     (1 << 5)
+#define GUC_CTX_DESC_ATTR_PCH          (1 << 6)
+
+/* The guc control data is 10 DWORDs */
+#define GUC_CTL_CTXINFO                        0
+#define   GUC_CTL_CTXNUM_IN16_SHIFT    0
+#define   GUC_CTL_BASE_ADDR_SHIFT      12
+#define GUC_CTL_ARAT_HIGH              1
+#define GUC_CTL_ARAT_LOW               2
+#define GUC_CTL_DEVICE_INFO            3
+#define   GUC_CTL_GTTYPE_SHIFT         0
+#define   GUC_CTL_COREFAMILY_SHIFT     7
+#define GUC_CTL_LOG_PARAMS             4
+#define   GUC_LOG_VALID                        (1 << 0)
+#define   GUC_LOG_NOTIFY_ON_HALF_FULL  (1 << 1)
+#define   GUC_LOG_ALLOC_IN_MEGABYTE    (1 << 3)
+#define   GUC_LOG_CRASH_PAGES          1
+#define   GUC_LOG_CRASH_SHIFT          4
+#define   GUC_LOG_DPC_PAGES            3
+#define   GUC_LOG_DPC_SHIFT            6
+#define   GUC_LOG_ISR_PAGES            3
+#define   GUC_LOG_ISR_SHIFT            9
+#define   GUC_LOG_BUF_ADDR_SHIFT       12
+#define GUC_CTL_PAGE_FAULT_CONTROL     5
+#define GUC_CTL_WA                     6
+#define   GUC_CTL_WA_UK_BY_DRIVER      (1 << 3)
+#define GUC_CTL_FEATURE                        7
+#define   GUC_CTL_VCS2_ENABLED         (1 << 0)
+#define   GUC_CTL_KERNEL_SUBMISSIONS   (1 << 1)
+#define   GUC_CTL_FEATURE2             (1 << 2)
+#define   GUC_CTL_POWER_GATING         (1 << 3)
+#define   GUC_CTL_DISABLE_SCHEDULER    (1 << 4)
+#define   GUC_CTL_PREEMPTION_LOG       (1 << 5)
+#define   GUC_CTL_ENABLE_SLPC          (1 << 7)
+#define GUC_CTL_DEBUG                  8
+#define   GUC_LOG_VERBOSITY_SHIFT      0
+#define   GUC_LOG_VERBOSITY_LOW                (0 << GUC_LOG_VERBOSITY_SHIFT)
+#define   GUC_LOG_VERBOSITY_MED                (1 << GUC_LOG_VERBOSITY_SHIFT)
+#define   GUC_LOG_VERBOSITY_HIGH       (2 << GUC_LOG_VERBOSITY_SHIFT)
+#define   GUC_LOG_VERBOSITY_ULTRA      (3 << GUC_LOG_VERBOSITY_SHIFT)
+/* Verbosity range-check limits, without the shift */
+#define          GUC_LOG_VERBOSITY_MIN         0
+#define          GUC_LOG_VERBOSITY_MAX         3
+
+#define GUC_CTL_MAX_DWORDS             (GUC_CTL_DEBUG + 1)
+
+struct guc_doorbell_info {
+       u32 db_status;
+       u32 cookie;
+       u32 reserved[14];
+} __packed;
+
+union guc_doorbell_qw {
+       struct {
+               u32 db_status;
+               u32 cookie;
+       };
+       u64 value_qw;
+} __packed;
+
+#define GUC_MAX_DOORBELLS              256
+#define GUC_INVALID_DOORBELL_ID                (GUC_MAX_DOORBELLS)
+
+#define GUC_DB_SIZE                    (PAGE_SIZE)
+#define GUC_WQ_SIZE                    (PAGE_SIZE * 2)
+
+/* Work item for submitting workloads into work queue of GuC. */
+struct guc_wq_item {
+       u32 header;
+       u32 context_desc;
+       u32 ring_tail;
+       u32 fence_id;
+} __packed;
+
+struct guc_process_desc {
+       u32 context_id;
+       u64 db_base_addr;
+       u32 head;
+       u32 tail;
+       u32 error_offset;
+       u64 wq_base_addr;
+       u32 wq_size_bytes;
+       u32 wq_status;
+       u32 engine_presence;
+       u32 priority;
+       u32 reserved[30];
+} __packed;
+
+/* engine id and context id is packed into guc_execlist_context.context_id*/
+#define GUC_ELC_CTXID_OFFSET           0
+#define GUC_ELC_ENGINE_OFFSET          29
+
+/* The execlist context including software and HW information */
+struct guc_execlist_context {
+       u32 context_desc;
+       u32 context_id;
+       u32 ring_status;
+       u32 ring_lcra;
+       u32 ring_begin;
+       u32 ring_end;
+       u32 ring_next_free_location;
+       u32 ring_current_tail_pointer_value;
+       u8 engine_state_submit_value;
+       u8 engine_state_wait_value;
+       u16 pagefault_count;
+       u16 engine_submit_queue_count;
+} __packed;
+
+/*Context descriptor for communicating between uKernel and Driver*/
+struct guc_context_desc {
+       u32 sched_common_area;
+       u32 context_id;
+       u32 pas_id;
+       u8 engines_used;
+       u64 db_trigger_cpu;
+       u32 db_trigger_uk;
+       u64 db_trigger_phy;
+       u16 db_id;
+
+       struct guc_execlist_context lrc[I915_NUM_RINGS];
+
+       u8 attribute;
+
+       u32 priority;
+
+       u32 wq_sampled_tail_offset;
+       u32 wq_total_submit_enqueues;
+
+       u32 process_desc;
+       u32 wq_addr;
+       u32 wq_size;
+
+       u32 engine_presence;
+
+       u32 reserved0[1];
+       u64 reserved1[1];
+
+       u64 desc_private;
+} __packed;
+
+/* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */
+enum host2guc_action {
+       HOST2GUC_ACTION_DEFAULT = 0x0,
+       HOST2GUC_ACTION_SAMPLE_FORCEWAKE = 0x6,
+       HOST2GUC_ACTION_ALLOCATE_DOORBELL = 0x10,
+       HOST2GUC_ACTION_DEALLOCATE_DOORBELL = 0x20,
+       HOST2GUC_ACTION_SLPC_REQUEST = 0x3003,
+       HOST2GUC_ACTION_LIMIT
+};
+
+/*
+ * The GuC sends its response to a command by overwriting the
+ * command in SS0. The response is distinguishable from a command
+ * by the fact that all the MASK bits are set. The remaining bits
+ * give more detail.
+ */
+#define        GUC2HOST_RESPONSE_MASK          ((u32)0xF0000000)
+#define        GUC2HOST_IS_RESPONSE(x)         ((u32)(x) >= GUC2HOST_RESPONSE_MASK)
+#define        GUC2HOST_STATUS(x)              (GUC2HOST_RESPONSE_MASK | (x))
+
+/* GUC will return status back to SOFT_SCRATCH_O_REG */
+enum guc2host_status {
+       GUC2HOST_STATUS_SUCCESS = GUC2HOST_STATUS(0x0),
+       GUC2HOST_STATUS_ALLOCATE_DOORBELL_FAIL = GUC2HOST_STATUS(0x10),
+       GUC2HOST_STATUS_DEALLOCATE_DOORBELL_FAIL = GUC2HOST_STATUS(0x20),
+       GUC2HOST_STATUS_GENERIC_FAIL = GUC2HOST_STATUS(0x0000F000)
+};
+
+#endif
index 70bad5bf1d48b9cc1c72afa360475487bf9b152e..51cbea8247fe9b2cfc6987e6dec114b06d09cc00 100644 (file)
@@ -1909,7 +1909,7 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
 }
 
 static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
-       .dpms = intel_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .detect = intel_hdmi_detect,
        .force = intel_hdmi_force,
        .fill_modes = drm_helper_probe_single_connector_modes,
index 3c9171f115310209d2e725f0b899d9d825baecdb..032a0bf75f3b1d4d7fbbfd44025653865f30ac0b 100644 (file)
  * it will use i915_hotplug_work_func where this logic is handled.
  */
 
-enum port intel_hpd_pin_to_port(enum hpd_pin pin)
+bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port)
 {
        switch (pin) {
+       case HPD_PORT_A:
+               *port = PORT_A;
+               return true;
        case HPD_PORT_B:
-               return PORT_B;
+               *port = PORT_B;
+               return true;
        case HPD_PORT_C:
-               return PORT_C;
+               *port = PORT_C;
+               return true;
        case HPD_PORT_D:
-               return PORT_D;
+               *port = PORT_D;
+               return true;
        default:
-               return PORT_A; /* no hpd */
+               return false;   /* no hpd */
        }
 }
 
@@ -369,8 +375,8 @@ void intel_hpd_irq_handler(struct drm_device *dev,
                if (!(BIT(i) & pin_mask))
                        continue;
 
-               port = intel_hpd_pin_to_port(i);
-               is_dig_port = port && dev_priv->hotplug.irq_port[port];
+               is_dig_port = intel_hpd_pin_to_port(i, &port) &&
+                             dev_priv->hotplug.irq_port[port];
 
                if (is_dig_port) {
                        bool long_hpd = long_mask & BIT(i);
index 9faad82c42ecd05fe599072bcaf25d49d05ae13b..5bc0ce1347cef5d7dd0e1c0397f2eefb4ba4e151 100644 (file)
@@ -497,6 +497,9 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring)
                status_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
                                (read_pointer % 6) * 8 + 4);
 
+               if (status & GEN8_CTX_STATUS_IDLE_ACTIVE)
+                       continue;
+
                if (status & GEN8_CTX_STATUS_PREEMPTED) {
                        if (status & GEN8_CTX_STATUS_LITE_RESTORE) {
                                if (execlists_check_remove_request(ring, status_id))
@@ -521,7 +524,7 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring)
        ring->next_context_status_buffer = write_pointer % 6;
 
        I915_WRITE(RING_CONTEXT_STATUS_PTR(ring),
-                  ((u32)ring->next_context_status_buffer & 0x07) << 8);
+                  _MASKED_FIELD(0x07 << 8, ((u32)ring->next_context_status_buffer & 0x07) << 8));
 }
 
 static int execlists_context_queue(struct drm_i915_gem_request *request)
@@ -1740,6 +1743,12 @@ static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req)
        if (ret)
                goto out;
 
+       ret = req->ring->emit_bb_start(req,
+                                      (so.ggtt_offset + so.aux_batch_offset),
+                                      I915_DISPATCH_SECURE);
+       if (ret)
+               goto out;
+
        i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req);
 
 out:
index cb634f48e7d96eff1a82371c44c28ba9948adefe..881b5d13592ef8075e64786c68e31050f6741d94 100644 (file)
@@ -549,7 +549,7 @@ static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs
 };
 
 static const struct drm_connector_funcs intel_lvds_connector_funcs = {
-       .dpms = intel_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .detect = intel_lvds_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_lvds_set_property,
index 5004c4a46a9e30aac110ba61a7116e983e74ba01..fff0c22682ee32f947907da7bb27f4fda0463073 100644 (file)
@@ -102,6 +102,12 @@ static void skl_init_clock_gating(struct drm_device *dev)
                /* WaDisableLSQCROPERFforOCL:skl */
                I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
                           GEN8_LQSC_RO_PERF_DIS);
+
+       /* WaEnableGapsTsvCreditFix:skl */
+       if (IS_SKYLAKE(dev) && (INTEL_REVID(dev) >= SKL_REVID_C0)) {
+               I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
+                                          GEN9_GAPS_TSV_CREDIT_DISABLE));
+       }
 }
 
 static void bxt_init_clock_gating(struct drm_device *dev)
@@ -4266,7 +4272,7 @@ static void ironlake_enable_drps(struct drm_device *dev)
 
        if (wait_for_atomic((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
                DRM_ERROR("stuck trying to change perf mode\n");
-       msleep(1);
+       mdelay(1);
 
        ironlake_set_drps(dev, fstart);
 
@@ -4297,10 +4303,10 @@ static void ironlake_disable_drps(struct drm_device *dev)
 
        /* Go back to the starting frequency */
        ironlake_set_drps(dev, dev_priv->ips.fstart);
-       msleep(1);
+       mdelay(1);
        rgvswctl |= MEMCTL_CMD_STS;
        I915_WRITE(MEMSWCTL, rgvswctl);
-       msleep(1);
+       mdelay(1);
 
        spin_unlock_irq(&mchdev_lock);
 }
index acd8ec859f71b8bd5a22dcaa8809b7bc552f29e4..a04b4dc5ed9b459ce42de39c12de74539a620066 100644 (file)
@@ -698,6 +698,7 @@ void intel_psr_flush(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
        enum pipe pipe;
+       int delay_ms = HAS_DDI(dev) ? 100 : 500;
 
        mutex_lock(&dev_priv->psr.lock);
        if (!dev_priv->psr.enabled) {
@@ -733,7 +734,7 @@ void intel_psr_flush(struct drm_device *dev,
 
        if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
                schedule_delayed_work(&dev_priv->psr.work,
-                                     msecs_to_jiffies(100));
+                                     msecs_to_jiffies(delay_ms));
        mutex_unlock(&dev_priv->psr.lock);
 }
 
index 177f7ed16cf0abbe6c2518b0a98ae7bf16a34b44..6e6b8db996ef2450c615a71ef10b7ffcbbc62479 100644 (file)
@@ -780,11 +780,11 @@ static int wa_add(struct drm_i915_private *dev_priv,
        return 0;
 }
 
-#define WA_REG(addr, mask, val) { \
+#define WA_REG(addr, mask, val) do { \
                const int r = wa_add(dev_priv, (addr), (mask), (val)); \
                if (r) \
                        return r; \
-       }
+       } while (0)
 
 #define WA_SET_BIT_MASKED(addr, mask) \
        WA_REG(addr, (mask), _MASKED_BIT_ENABLE(mask))
@@ -1041,13 +1041,6 @@ static int skl_init_workarounds(struct intel_engine_cs *ring)
                WA_SET_BIT_MASKED(HIZ_CHICKEN,
                                  BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE);
 
-       if (INTEL_REVID(dev) == SKL_REVID_C0 ||
-           INTEL_REVID(dev) == SKL_REVID_D0)
-               /* WaBarrierPerformanceFixDisable:skl */
-               WA_SET_BIT_MASKED(HDC_CHICKEN0,
-                                 HDC_FENCE_DEST_SLM_DISABLE |
-                                 HDC_BARRIER_PERFORMANCE_DISABLE);
-
        if (INTEL_REVID(dev) <= SKL_REVID_D0) {
                /*
                 *Use Force Non-Coherent whenever executing a 3D context. This
@@ -1066,6 +1059,13 @@ static int skl_init_workarounds(struct intel_engine_cs *ring)
                                  HDC_FENCE_DEST_SLM_DISABLE |
                                  HDC_BARRIER_PERFORMANCE_DISABLE);
 
+       /* WaDisableSbeCacheDispatchPortSharing:skl */
+       if (INTEL_REVID(dev) <= SKL_REVID_F0) {
+               WA_SET_BIT_MASKED(
+                       GEN7_HALF_SLICE_CHICKEN1,
+                       GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
+       }
+
        return skl_tune_iz_hashing(ring);
 }
 
index 6393b76f87ffa57e48134bab5805411ee1bd2354..821644d1b544eb618e57db8196014768ebe9d7b8 100644 (file)
 bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
                                    int power_well_id);
 
+static void intel_power_well_enable(struct drm_i915_private *dev_priv,
+                                   struct i915_power_well *power_well)
+{
+       DRM_DEBUG_KMS("enabling %s\n", power_well->name);
+       power_well->ops->enable(dev_priv, power_well);
+       power_well->hw_enabled = true;
+}
+
+static void intel_power_well_disable(struct drm_i915_private *dev_priv,
+                                    struct i915_power_well *power_well)
+{
+       DRM_DEBUG_KMS("disabling %s\n", power_well->name);
+       power_well->hw_enabled = false;
+       power_well->ops->disable(dev_priv, power_well);
+}
+
 /*
  * We should only use the power well if we explicitly asked the hardware to
  * enable it, so check if it's enabled and also check if we've requested it to
@@ -1104,11 +1120,8 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
        mutex_lock(&power_domains->lock);
 
        for_each_power_well(i, power_well, BIT(domain), power_domains) {
-               if (!power_well->count++) {
-                       DRM_DEBUG_KMS("enabling %s\n", power_well->name);
-                       power_well->ops->enable(dev_priv, power_well);
-                       power_well->hw_enabled = true;
-               }
+               if (!power_well->count++)
+                       intel_power_well_enable(dev_priv, power_well);
        }
 
        power_domains->domain_use_count[domain]++;
@@ -1142,11 +1155,8 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
        for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
                WARN_ON(!power_well->count);
 
-               if (!--power_well->count && i915.disable_power_well) {
-                       DRM_DEBUG_KMS("disabling %s\n", power_well->name);
-                       power_well->hw_enabled = false;
-                       power_well->ops->disable(dev_priv, power_well);
-               }
+               if (!--power_well->count && i915.disable_power_well)
+                       intel_power_well_disable(dev_priv, power_well);
        }
 
        mutex_unlock(&power_domains->lock);
index aa2fd751609cf2be92826d4f8e6ba85df971892e..c98098e884ccef64e7d722a70063bd97b404a7cc 100644 (file)
@@ -1508,51 +1508,6 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)
        intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
 }
 
-/* Special dpms function to support cloning between dvo/sdvo/crt. */
-static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
-{
-       struct drm_crtc *crtc;
-       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
-
-       /* dvo supports only 2 dpms states. */
-       if (mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
-
-       if (mode == connector->dpms)
-               return;
-
-       connector->dpms = mode;
-
-       /* Only need to change hw state when actually enabled */
-       crtc = intel_sdvo->base.base.crtc;
-       if (!crtc) {
-               intel_sdvo->base.connectors_active = false;
-               return;
-       }
-
-       /* We set active outputs manually below in case pipe dpms doesn't change
-        * due to cloning. */
-       if (mode != DRM_MODE_DPMS_ON) {
-               intel_sdvo_set_active_outputs(intel_sdvo, 0);
-               if (0)
-                       intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
-
-               intel_sdvo->base.connectors_active = false;
-
-               intel_crtc_update_dpms(crtc);
-       } else {
-               intel_sdvo->base.connectors_active = true;
-
-               intel_crtc_update_dpms(crtc);
-
-               if (0)
-                       intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
-               intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
-       }
-
-       intel_modeset_check_state(connector->dev);
-}
-
 static enum drm_mode_status
 intel_sdvo_mode_valid(struct drm_connector *connector,
                      struct drm_display_mode *mode)
@@ -2190,7 +2145,7 @@ done:
 }
 
 static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
-       .dpms = intel_sdvo_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .detect = intel_sdvo_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_sdvo_set_property,
index 8b9d325bda3c7e1c73af68afb6dc46ac3cb9d4fc..0568ae6ec9dd2c945b0395a14305c281daf18be2 100644 (file)
@@ -1509,7 +1509,7 @@ out:
 }
 
 static const struct drm_connector_funcs intel_tv_connector_funcs = {
-       .dpms = intel_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .detect = intel_tv_detect,
        .destroy = intel_tv_destroy,
        .set_property = intel_tv_set_property,
index 45285a9178fe10e1fd1f4db25547a7a51b52853e..9d3c2e420d2b68611d52e9c6395d35721da19447 100644 (file)
@@ -1274,10 +1274,12 @@ int i915_reg_read_ioctl(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_reg_read *reg = data;
        struct register_whitelist const *entry = whitelist;
+       unsigned size;
+       u64 offset;
        int i, ret = 0;
 
        for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) {
-               if (entry->offset == reg->offset &&
+               if (entry->offset == (reg->offset & -entry->size) &&
                    (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask))
                        break;
        }
@@ -1285,23 +1287,33 @@ int i915_reg_read_ioctl(struct drm_device *dev,
        if (i == ARRAY_SIZE(whitelist))
                return -EINVAL;
 
+       /* We use the low bits to encode extra flags as the register should
+        * be naturally aligned (and those that are not so aligned merely
+        * limit the available flags for that register).
+        */
+       offset = entry->offset;
+       size = entry->size;
+       size |= reg->offset ^ offset;
+
        intel_runtime_pm_get(dev_priv);
 
-       switch (entry->size) {
+       switch (size) {
+       case 8 | 1:
+               reg->val = I915_READ64_2x32(offset, offset+4);
+               break;
        case 8:
-               reg->val = I915_READ64(reg->offset);
+               reg->val = I915_READ64(offset);
                break;
        case 4:
-               reg->val = I915_READ(reg->offset);
+               reg->val = I915_READ(offset);
                break;
        case 2:
-               reg->val = I915_READ16(reg->offset);
+               reg->val = I915_READ16(offset);
                break;
        case 1:
-               reg->val = I915_READ8(reg->offset);
+               reg->val = I915_READ8(offset);
                break;
        default:
-               MISSING_CASE(entry->size);
                ret = -EINVAL;
                goto out;
        }
index 9f9780b7ddf0be7d3a82ba77205d21d29984b02f..4f2068fe5d885cdba438a44745c27ccade5df9d0 100644 (file)
@@ -70,18 +70,22 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc,
        BUG_ON(pixels_2 != pixels_current && pixels_2 != pixels_prev);
        BUG_ON(pixels_current == pixels_prev);
 
+       obj = drm_gem_object_lookup(dev, file_priv, handle);
+       if (!obj)
+               return -ENOENT;
+
        ret = mgag200_bo_reserve(pixels_1, true);
        if (ret) {
                WREG8(MGA_CURPOSXL, 0);
                WREG8(MGA_CURPOSXH, 0);
-               return ret;
+               goto out_unref;
        }
        ret = mgag200_bo_reserve(pixels_2, true);
        if (ret) {
                WREG8(MGA_CURPOSXL, 0);
                WREG8(MGA_CURPOSXH, 0);
                mgag200_bo_unreserve(pixels_1);
-               return ret;
+               goto out_unreserve1;
        }
 
        if (!handle) {
@@ -106,16 +110,6 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc,
                }
        }
 
-       mutex_lock(&dev->struct_mutex);
-       obj = drm_gem_object_lookup(dev, file_priv, handle);
-       if (!obj) {
-               mutex_unlock(&dev->struct_mutex);
-               ret = -ENOENT;
-               goto out1;
-       }
-       drm_gem_object_unreference(obj);
-       mutex_unlock(&dev->struct_mutex);
-
        bo = gem_to_mga_bo(obj);
        ret = mgag200_bo_reserve(bo, true);
        if (ret) {
@@ -252,7 +246,11 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc,
        if (ret)
                mga_hide_cursor(mdev);
        mgag200_bo_unreserve(pixels_1);
+out_unreserve1:
        mgag200_bo_unreserve(pixels_2);
+out_unref:
+       drm_gem_object_unreference_unlocked(obj);
+
        return ret;
 }
 
index 958cf3cf082dcbef92a0d7926ff98d65a6484c23..87de15ea1f93fd72cc05ad358995b313d75a1b76 100644 (file)
@@ -101,7 +101,7 @@ static void mga_fillrect(struct fb_info *info,
                         const struct fb_fillrect *rect)
 {
        struct mga_fbdev *mfbdev = info->par;
-       sys_fillrect(info, rect);
+       drm_fb_helper_sys_fillrect(info, rect);
        mga_dirty_update(mfbdev, rect->dx, rect->dy, rect->width,
                         rect->height);
 }
@@ -110,7 +110,7 @@ static void mga_copyarea(struct fb_info *info,
                         const struct fb_copyarea *area)
 {
        struct mga_fbdev *mfbdev = info->par;
-       sys_copyarea(info, area);
+       drm_fb_helper_sys_copyarea(info, area);
        mga_dirty_update(mfbdev, area->dx, area->dy, area->width,
                         area->height);
 }
@@ -119,7 +119,7 @@ static void mga_imageblit(struct fb_info *info,
                          const struct fb_image *image)
 {
        struct mga_fbdev *mfbdev = info->par;
-       sys_imageblit(info, image);
+       drm_fb_helper_sys_imageblit(info, image);
        mga_dirty_update(mfbdev, image->dx, image->dy, image->width,
                         image->height);
 }
@@ -166,7 +166,6 @@ static int mgag200fb_create(struct drm_fb_helper *helper,
        struct fb_info *info;
        struct drm_framebuffer *fb;
        struct drm_gem_object *gobj = NULL;
-       struct device *device = &dev->pdev->dev;
        int ret;
        void *sysram;
        int size;
@@ -189,9 +188,9 @@ static int mgag200fb_create(struct drm_fb_helper *helper,
        if (!sysram)
                return -ENOMEM;
 
-       info = framebuffer_alloc(0, device);
-       if (info == NULL)
-               return -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info))
+               return PTR_ERR(info);
 
        info->par = mfbdev;
 
@@ -206,14 +205,6 @@ static int mgag200fb_create(struct drm_fb_helper *helper,
 
        /* setup helper */
        mfbdev->helper.fb = fb;
-       mfbdev->helper.fbdev = info;
-
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               DRM_ERROR("%s: can't allocate color map\n", info->fix.id);
-               ret = -ENOMEM;
-               goto out;
-       }
 
        strcpy(info->fix.id, "mgadrmfb");
 
@@ -221,11 +212,6 @@ static int mgag200fb_create(struct drm_fb_helper *helper,
        info->fbops = &mgag200fb_ops;
 
        /* setup aperture base/size for vesafb takeover */
-       info->apertures = alloc_apertures(1);
-       if (!info->apertures) {
-               ret = -ENOMEM;
-               goto out;
-       }
        info->apertures->ranges[0].base = mdev->dev->mode_config.fb_base;
        info->apertures->ranges[0].size = mdev->mc.vram_size;
 
@@ -240,24 +226,15 @@ static int mgag200fb_create(struct drm_fb_helper *helper,
        DRM_DEBUG_KMS("allocated %dx%d\n",
                      fb->width, fb->height);
        return 0;
-out:
-       return ret;
 }
 
 static int mga_fbdev_destroy(struct drm_device *dev,
                                struct mga_fbdev *mfbdev)
 {
-       struct fb_info *info;
        struct mga_framebuffer *mfb = &mfbdev->mfb;
 
-       if (mfbdev->helper.fbdev) {
-               info = mfbdev->helper.fbdev;
-
-               unregister_framebuffer(info);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&mfbdev->helper);
+       drm_fb_helper_release_fbi(&mfbdev->helper);
 
        if (mfb->obj) {
                drm_gem_object_unreference_unlocked(mfb->obj);
index f6b283b8375ec7071adb32459a1bc2f6427dc2ad..c99c2cb2893907e0154cb73b4f354508502a197c 100644 (file)
@@ -345,23 +345,15 @@ mgag200_dumb_mmap_offset(struct drm_file *file,
                     uint64_t *offset)
 {
        struct drm_gem_object *obj;
-       int ret;
        struct mgag200_bo *bo;
 
-       mutex_lock(&dev->struct_mutex);
        obj = drm_gem_object_lookup(dev, file, handle);
-       if (obj == NULL) {
-               ret = -ENOENT;
-               goto out_unlock;
-       }
+       if (obj == NULL)
+               return -ENOENT;
 
        bo = gem_to_mga_bo(obj);
        *offset = mgag200_bo_mmap_offset(bo);
 
-       drm_gem_object_unreference(obj);
-       ret = 0;
-out_unlock:
-       mutex_unlock(&dev->struct_mutex);
-       return ret;
-
+       drm_gem_object_unreference_unlocked(obj);
+       return 0;
 }
index 08ba8d0d93f5ba9509541cb371a9128e25761d28..8e6c7c638e24b8f6c81c0061686bb7393dbbc642 100644 (file)
@@ -9,6 +9,7 @@ config DRM_MSM
        select DRM_PANEL
        select SHMEM
        select TMPFS
+       select QCOM_SCM
        default y
        help
          DRM/KMS driver for MSM/snapdragon.
@@ -53,3 +54,17 @@ config DRM_MSM_DSI_PLL
        help
          Choose this option to enable DSI PLL driver which provides DSI
          source clocks under common clock framework.
+
+config DRM_MSM_DSI_28NM_PHY
+       bool "Enable DSI 28nm PHY driver in MSM DRM"
+       depends on DRM_MSM_DSI
+       default y
+       help
+         Choose this option if the 28nm DSI PHY is used on the platform.
+
+config DRM_MSM_DSI_20NM_PHY
+       bool "Enable DSI 20nm PHY driver in MSM DRM"
+       depends on DRM_MSM_DSI
+       default y
+       help
+         Choose this option if the 20nm DSI PHY is used on the platform.
index 16a81b94d6f0b2345627cfc784c0825661a5ed29..0a543eb5e5d7c0e3c821fcf26ce78dffe474901f 100644 (file)
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm
-ccflags-$(CONFIG_DRM_MSM_DSI_PLL) += -Idrivers/gpu/drm/msm/dsi
+ccflags-$(CONFIG_DRM_MSM_DSI) += -Idrivers/gpu/drm/msm/dsi
 
 msm-y := \
        adreno/adreno_device.o \
@@ -10,6 +10,7 @@ msm-y := \
        hdmi/hdmi_audio.o \
        hdmi/hdmi_bridge.o \
        hdmi/hdmi_connector.o \
+       hdmi/hdmi_hdcp.o \
        hdmi/hdmi_i2c.o \
        hdmi/hdmi_phy_8960.o \
        hdmi/hdmi_phy_8x60.o \
@@ -53,12 +54,18 @@ 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_cfg.o \
                        dsi/dsi_host.o \
                        dsi/dsi_manager.o \
-                       dsi/dsi_phy.o \
+                       dsi/phy/dsi_phy.o \
                        mdp/mdp5/mdp5_cmd_encoder.o
 
-msm-$(CONFIG_DRM_MSM_DSI_PLL) += dsi/pll/dsi_pll.o \
-                               dsi/pll/dsi_pll_28nm.o
+msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o
+msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o
+
+ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y)
+msm-y += dsi/pll/dsi_pll.o
+msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o
+endif
 
 obj-$(CONFIG_DRM_MSM)  += msm.o
index 23176e402796f4a3eb925c1c5fe02ec6cd666ceb..0261f0d3161278a66ed3a8b004724b74192ed1aa 100644 (file)
@@ -8,15 +8,15 @@ http://github.com/freedreno/envytools/
 git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14895 bytes, from 2015-04-19 15:23:28)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  66709 bytes, from 2015-04-12 18:16:35)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  60633 bytes, from 2015-05-20 14:48:19)
-
-Copyright (C) 2013-2014 by the following authors:
+- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14968 bytes, from 2015-05-20 20:12:27)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  67120 bytes, from 2015-08-14 23:22:03)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  63785 bytes, from 2015-08-14 18:27:06)
+
+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
index 1c599e5cf318626f04c198271e69656d03046a36..48d133711487acc10292926cd22371a85ab55fd1 100644 (file)
@@ -8,13 +8,13 @@ http://github.com/freedreno/envytools/
 git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14895 bytes, from 2015-04-19 15:23:28)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  66709 bytes, from 2015-04-12 18:16:35)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  60633 bytes, from 2015-05-20 14:48:19)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14968 bytes, from 2015-05-20 20:12:27)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  67120 bytes, from 2015-08-14 23:22:03)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  63785 bytes, from 2015-08-14 18:27:06)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -326,6 +326,13 @@ enum a3xx_tex_type {
        A3XX_TEX_3D = 3,
 };
 
+enum a3xx_tex_msaa {
+       A3XX_TPL1_MSAA1X = 0,
+       A3XX_TPL1_MSAA2X = 1,
+       A3XX_TPL1_MSAA4X = 2,
+       A3XX_TPL1_MSAA8X = 3,
+};
+
 #define A3XX_INT0_RBBM_GPU_IDLE                                        0x00000001
 #define A3XX_INT0_RBBM_AHB_ERROR                               0x00000002
 #define A3XX_INT0_RBBM_REG_TIMEOUT                             0x00000004
@@ -2652,6 +2659,7 @@ static inline uint32_t A3XX_VGT_DRAW_INITIATOR_NUM_INSTANCES(uint32_t val)
 #define REG_A3XX_VGT_IMMED_DATA                                        0x000021fd
 
 #define REG_A3XX_TEX_SAMP_0                                    0x00000000
+#define A3XX_TEX_SAMP_0_CLAMPENABLE                            0x00000001
 #define A3XX_TEX_SAMP_0_MIPFILTER_LINEAR                       0x00000002
 #define A3XX_TEX_SAMP_0_XY_MAG__MASK                           0x0000000c
 #define A3XX_TEX_SAMP_0_XY_MAG__SHIFT                          2
@@ -2695,6 +2703,7 @@ static inline uint32_t A3XX_TEX_SAMP_0_COMPARE_FUNC(enum adreno_compare_func val
 {
        return ((val) << A3XX_TEX_SAMP_0_COMPARE_FUNC__SHIFT) & A3XX_TEX_SAMP_0_COMPARE_FUNC__MASK;
 }
+#define A3XX_TEX_SAMP_0_CUBEMAPSEAMLESSFILTOFF                 0x01000000
 #define A3XX_TEX_SAMP_0_UNNORM_COORDS                          0x80000000
 
 #define REG_A3XX_TEX_SAMP_1                                    0x00000001
@@ -2750,6 +2759,12 @@ static inline uint32_t A3XX_TEX_CONST_0_MIPLVLS(uint32_t val)
 {
        return ((val) << A3XX_TEX_CONST_0_MIPLVLS__SHIFT) & A3XX_TEX_CONST_0_MIPLVLS__MASK;
 }
+#define A3XX_TEX_CONST_0_MSAATEX__MASK                         0x00300000
+#define A3XX_TEX_CONST_0_MSAATEX__SHIFT                                20
+static inline uint32_t A3XX_TEX_CONST_0_MSAATEX(enum a3xx_tex_msaa val)
+{
+       return ((val) << A3XX_TEX_CONST_0_MSAATEX__SHIFT) & A3XX_TEX_CONST_0_MSAATEX__MASK;
+}
 #define A3XX_TEX_CONST_0_FMT__MASK                             0x1fc00000
 #define A3XX_TEX_CONST_0_FMT__SHIFT                            22
 static inline uint32_t A3XX_TEX_CONST_0_FMT(enum a3xx_tex_fmt val)
@@ -2785,7 +2800,7 @@ static inline uint32_t A3XX_TEX_CONST_1_FETCHSIZE(enum a3xx_tex_fetchsize val)
 }
 
 #define REG_A3XX_TEX_CONST_2                                   0x00000002
-#define A3XX_TEX_CONST_2_INDX__MASK                            0x000000ff
+#define A3XX_TEX_CONST_2_INDX__MASK                            0x000001ff
 #define A3XX_TEX_CONST_2_INDX__SHIFT                           0
 static inline uint32_t A3XX_TEX_CONST_2_INDX(uint32_t val)
 {
@@ -2805,7 +2820,7 @@ static inline uint32_t A3XX_TEX_CONST_2_SWAP(enum a3xx_color_swap val)
 }
 
 #define REG_A3XX_TEX_CONST_3                                   0x00000003
-#define A3XX_TEX_CONST_3_LAYERSZ1__MASK                                0x00007fff
+#define A3XX_TEX_CONST_3_LAYERSZ1__MASK                                0x0001ffff
 #define A3XX_TEX_CONST_3_LAYERSZ1__SHIFT                       0
 static inline uint32_t A3XX_TEX_CONST_3_LAYERSZ1(uint32_t val)
 {
index 3f06ecf62583af3e1c247abdbc4bf47dd5850a44..ac55066db3b012d9bb2a35df52c28d7ccf1768de 100644 (file)
@@ -8,13 +8,13 @@ http://github.com/freedreno/envytools/
 git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14895 bytes, from 2015-04-19 15:23:28)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  66709 bytes, from 2015-04-12 18:16:35)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  60633 bytes, from 2015-05-20 14:48:19)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14968 bytes, from 2015-05-20 20:12:27)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  67120 bytes, from 2015-08-14 23:22:03)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  63785 bytes, from 2015-08-14 18:27:06)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -227,6 +227,7 @@ enum a4xx_depth_format {
        DEPTH4_NONE = 0,
        DEPTH4_16 = 1,
        DEPTH4_24_8 = 2,
+       DEPTH4_32 = 3,
 };
 
 enum a4xx_tess_spacing {
@@ -429,7 +430,7 @@ static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_SWAP(enum a3xx_color_swap val)
        return ((val) << A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT) & A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK;
 }
 #define A4XX_RB_MRT_BUF_INFO_COLOR_SRGB                                0x00002000
-#define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK             0x007fc000
+#define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK             0xffffc000
 #define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__SHIFT            14
 static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(uint32_t val)
 {
@@ -439,7 +440,7 @@ static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(uint32_t val)
 static inline uint32_t REG_A4XX_RB_MRT_BASE(uint32_t i0) { return 0x000020a6 + 0x5*i0; }
 
 static inline uint32_t REG_A4XX_RB_MRT_CONTROL3(uint32_t i0) { return 0x000020a7 + 0x5*i0; }
-#define A4XX_RB_MRT_CONTROL3_STRIDE__MASK                      0x0001fff8
+#define A4XX_RB_MRT_CONTROL3_STRIDE__MASK                      0x03fffff8
 #define A4XX_RB_MRT_CONTROL3_STRIDE__SHIFT                     3
 static inline uint32_t A4XX_RB_MRT_CONTROL3_STRIDE(uint32_t val)
 {
@@ -570,6 +571,15 @@ static inline uint32_t A4XX_RB_FS_OUTPUT_SAMPLE_MASK(uint32_t val)
        return ((val) << A4XX_RB_FS_OUTPUT_SAMPLE_MASK__SHIFT) & A4XX_RB_FS_OUTPUT_SAMPLE_MASK__MASK;
 }
 
+#define REG_A4XX_RB_SAMPLE_COUNT_CONTROL                       0x000020fa
+#define A4XX_RB_SAMPLE_COUNT_CONTROL_COPY                      0x00000002
+#define A4XX_RB_SAMPLE_COUNT_CONTROL_ADDR__MASK                        0xfffffffc
+#define A4XX_RB_SAMPLE_COUNT_CONTROL_ADDR__SHIFT               2
+static inline uint32_t A4XX_RB_SAMPLE_COUNT_CONTROL_ADDR(uint32_t val)
+{
+       return ((val >> 2) << A4XX_RB_SAMPLE_COUNT_CONTROL_ADDR__SHIFT) & A4XX_RB_SAMPLE_COUNT_CONTROL_ADDR__MASK;
+}
+
 #define REG_A4XX_RB_RENDER_COMPONENTS                          0x000020fb
 #define A4XX_RB_RENDER_COMPONENTS_RT0__MASK                    0x0000000f
 #define A4XX_RB_RENDER_COMPONENTS_RT0__SHIFT                   0
@@ -811,6 +821,23 @@ static inline uint32_t A4XX_RB_STENCIL_CONTROL_ZFAIL_BF(enum adreno_stencil_op v
 #define REG_A4XX_RB_STENCIL_CONTROL2                           0x00002107
 #define A4XX_RB_STENCIL_CONTROL2_STENCIL_BUFFER                        0x00000001
 
+#define REG_A4XX_RB_STENCIL_INFO                               0x00002108
+#define A4XX_RB_STENCIL_INFO_SEPARATE_STENCIL                  0x00000001
+#define A4XX_RB_STENCIL_INFO_STENCIL_BASE__MASK                        0xfffff000
+#define A4XX_RB_STENCIL_INFO_STENCIL_BASE__SHIFT               12
+static inline uint32_t A4XX_RB_STENCIL_INFO_STENCIL_BASE(uint32_t val)
+{
+       return ((val >> 12) << A4XX_RB_STENCIL_INFO_STENCIL_BASE__SHIFT) & A4XX_RB_STENCIL_INFO_STENCIL_BASE__MASK;
+}
+
+#define REG_A4XX_RB_STENCIL_PITCH                              0x00002109
+#define A4XX_RB_STENCIL_PITCH__MASK                            0xffffffff
+#define A4XX_RB_STENCIL_PITCH__SHIFT                           0
+static inline uint32_t A4XX_RB_STENCIL_PITCH(uint32_t val)
+{
+       return ((val >> 5) << A4XX_RB_STENCIL_PITCH__SHIFT) & A4XX_RB_STENCIL_PITCH__MASK;
+}
+
 #define REG_A4XX_RB_STENCILREFMASK                             0x0000210b
 #define A4XX_RB_STENCILREFMASK_STENCILREF__MASK                        0x000000ff
 #define A4XX_RB_STENCILREFMASK_STENCILREF__SHIFT               0
@@ -1433,6 +1460,7 @@ static inline uint32_t A4XX_SP_FS_MRT_REG_MRTFORMAT(enum a4xx_color_fmt val)
 {
        return ((val) << A4XX_SP_FS_MRT_REG_MRTFORMAT__SHIFT) & A4XX_SP_FS_MRT_REG_MRTFORMAT__MASK;
 }
+#define A4XX_SP_FS_MRT_REG_COLOR_SRGB                          0x00040000
 
 #define REG_A4XX_SP_CS_CTRL_REG0                               0x00002300
 
@@ -1470,6 +1498,76 @@ static inline uint32_t A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
 
 #define REG_A4XX_SP_HS_LENGTH_REG                              0x00002312
 
+#define REG_A4XX_SP_DS_PARAM_REG                               0x0000231a
+#define A4XX_SP_DS_PARAM_REG_POSREGID__MASK                    0x000000ff
+#define A4XX_SP_DS_PARAM_REG_POSREGID__SHIFT                   0
+static inline uint32_t A4XX_SP_DS_PARAM_REG_POSREGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_PARAM_REG_POSREGID__SHIFT) & A4XX_SP_DS_PARAM_REG_POSREGID__MASK;
+}
+#define A4XX_SP_DS_PARAM_REG_TOTALGSOUTVAR__MASK               0xfff00000
+#define A4XX_SP_DS_PARAM_REG_TOTALGSOUTVAR__SHIFT              20
+static inline uint32_t A4XX_SP_DS_PARAM_REG_TOTALGSOUTVAR(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_PARAM_REG_TOTALGSOUTVAR__SHIFT) & A4XX_SP_DS_PARAM_REG_TOTALGSOUTVAR__MASK;
+}
+
+static inline uint32_t REG_A4XX_SP_DS_OUT(uint32_t i0) { return 0x0000231b + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_SP_DS_OUT_REG(uint32_t i0) { return 0x0000231b + 0x1*i0; }
+#define A4XX_SP_DS_OUT_REG_A_REGID__MASK                       0x000001ff
+#define A4XX_SP_DS_OUT_REG_A_REGID__SHIFT                      0
+static inline uint32_t A4XX_SP_DS_OUT_REG_A_REGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_OUT_REG_A_REGID__SHIFT) & A4XX_SP_DS_OUT_REG_A_REGID__MASK;
+}
+#define A4XX_SP_DS_OUT_REG_A_COMPMASK__MASK                    0x00001e00
+#define A4XX_SP_DS_OUT_REG_A_COMPMASK__SHIFT                   9
+static inline uint32_t A4XX_SP_DS_OUT_REG_A_COMPMASK(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_OUT_REG_A_COMPMASK__SHIFT) & A4XX_SP_DS_OUT_REG_A_COMPMASK__MASK;
+}
+#define A4XX_SP_DS_OUT_REG_B_REGID__MASK                       0x01ff0000
+#define A4XX_SP_DS_OUT_REG_B_REGID__SHIFT                      16
+static inline uint32_t A4XX_SP_DS_OUT_REG_B_REGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_OUT_REG_B_REGID__SHIFT) & A4XX_SP_DS_OUT_REG_B_REGID__MASK;
+}
+#define A4XX_SP_DS_OUT_REG_B_COMPMASK__MASK                    0x1e000000
+#define A4XX_SP_DS_OUT_REG_B_COMPMASK__SHIFT                   25
+static inline uint32_t A4XX_SP_DS_OUT_REG_B_COMPMASK(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_OUT_REG_B_COMPMASK__SHIFT) & A4XX_SP_DS_OUT_REG_B_COMPMASK__MASK;
+}
+
+static inline uint32_t REG_A4XX_SP_DS_VPC_DST(uint32_t i0) { return 0x0000232c + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_SP_DS_VPC_DST_REG(uint32_t i0) { return 0x0000232c + 0x1*i0; }
+#define A4XX_SP_DS_VPC_DST_REG_OUTLOC0__MASK                   0x000000ff
+#define A4XX_SP_DS_VPC_DST_REG_OUTLOC0__SHIFT                  0
+static inline uint32_t A4XX_SP_DS_VPC_DST_REG_OUTLOC0(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_VPC_DST_REG_OUTLOC0__SHIFT) & A4XX_SP_DS_VPC_DST_REG_OUTLOC0__MASK;
+}
+#define A4XX_SP_DS_VPC_DST_REG_OUTLOC1__MASK                   0x0000ff00
+#define A4XX_SP_DS_VPC_DST_REG_OUTLOC1__SHIFT                  8
+static inline uint32_t A4XX_SP_DS_VPC_DST_REG_OUTLOC1(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_VPC_DST_REG_OUTLOC1__SHIFT) & A4XX_SP_DS_VPC_DST_REG_OUTLOC1__MASK;
+}
+#define A4XX_SP_DS_VPC_DST_REG_OUTLOC2__MASK                   0x00ff0000
+#define A4XX_SP_DS_VPC_DST_REG_OUTLOC2__SHIFT                  16
+static inline uint32_t A4XX_SP_DS_VPC_DST_REG_OUTLOC2(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_VPC_DST_REG_OUTLOC2__SHIFT) & A4XX_SP_DS_VPC_DST_REG_OUTLOC2__MASK;
+}
+#define A4XX_SP_DS_VPC_DST_REG_OUTLOC3__MASK                   0xff000000
+#define A4XX_SP_DS_VPC_DST_REG_OUTLOC3__SHIFT                  24
+static inline uint32_t A4XX_SP_DS_VPC_DST_REG_OUTLOC3(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_VPC_DST_REG_OUTLOC3__SHIFT) & A4XX_SP_DS_VPC_DST_REG_OUTLOC3__MASK;
+}
+
 #define REG_A4XX_SP_DS_OBJ_OFFSET_REG                          0x00002334
 #define A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK      0x01ff0000
 #define A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT     16
@@ -1492,6 +1590,82 @@ static inline uint32_t A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
 
 #define REG_A4XX_SP_DS_LENGTH_REG                              0x00002339
 
+#define REG_A4XX_SP_GS_PARAM_REG                               0x00002341
+#define A4XX_SP_GS_PARAM_REG_POSREGID__MASK                    0x000000ff
+#define A4XX_SP_GS_PARAM_REG_POSREGID__SHIFT                   0
+static inline uint32_t A4XX_SP_GS_PARAM_REG_POSREGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_PARAM_REG_POSREGID__SHIFT) & A4XX_SP_GS_PARAM_REG_POSREGID__MASK;
+}
+#define A4XX_SP_GS_PARAM_REG_PRIMREGID__MASK                   0x0000ff00
+#define A4XX_SP_GS_PARAM_REG_PRIMREGID__SHIFT                  8
+static inline uint32_t A4XX_SP_GS_PARAM_REG_PRIMREGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_PARAM_REG_PRIMREGID__SHIFT) & A4XX_SP_GS_PARAM_REG_PRIMREGID__MASK;
+}
+#define A4XX_SP_GS_PARAM_REG_TOTALGSOUTVAR__MASK               0xfff00000
+#define A4XX_SP_GS_PARAM_REG_TOTALGSOUTVAR__SHIFT              20
+static inline uint32_t A4XX_SP_GS_PARAM_REG_TOTALGSOUTVAR(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_PARAM_REG_TOTALGSOUTVAR__SHIFT) & A4XX_SP_GS_PARAM_REG_TOTALGSOUTVAR__MASK;
+}
+
+static inline uint32_t REG_A4XX_SP_GS_OUT(uint32_t i0) { return 0x00002342 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_SP_GS_OUT_REG(uint32_t i0) { return 0x00002342 + 0x1*i0; }
+#define A4XX_SP_GS_OUT_REG_A_REGID__MASK                       0x000001ff
+#define A4XX_SP_GS_OUT_REG_A_REGID__SHIFT                      0
+static inline uint32_t A4XX_SP_GS_OUT_REG_A_REGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_OUT_REG_A_REGID__SHIFT) & A4XX_SP_GS_OUT_REG_A_REGID__MASK;
+}
+#define A4XX_SP_GS_OUT_REG_A_COMPMASK__MASK                    0x00001e00
+#define A4XX_SP_GS_OUT_REG_A_COMPMASK__SHIFT                   9
+static inline uint32_t A4XX_SP_GS_OUT_REG_A_COMPMASK(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_OUT_REG_A_COMPMASK__SHIFT) & A4XX_SP_GS_OUT_REG_A_COMPMASK__MASK;
+}
+#define A4XX_SP_GS_OUT_REG_B_REGID__MASK                       0x01ff0000
+#define A4XX_SP_GS_OUT_REG_B_REGID__SHIFT                      16
+static inline uint32_t A4XX_SP_GS_OUT_REG_B_REGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_OUT_REG_B_REGID__SHIFT) & A4XX_SP_GS_OUT_REG_B_REGID__MASK;
+}
+#define A4XX_SP_GS_OUT_REG_B_COMPMASK__MASK                    0x1e000000
+#define A4XX_SP_GS_OUT_REG_B_COMPMASK__SHIFT                   25
+static inline uint32_t A4XX_SP_GS_OUT_REG_B_COMPMASK(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_OUT_REG_B_COMPMASK__SHIFT) & A4XX_SP_GS_OUT_REG_B_COMPMASK__MASK;
+}
+
+static inline uint32_t REG_A4XX_SP_GS_VPC_DST(uint32_t i0) { return 0x00002353 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_SP_GS_VPC_DST_REG(uint32_t i0) { return 0x00002353 + 0x1*i0; }
+#define A4XX_SP_GS_VPC_DST_REG_OUTLOC0__MASK                   0x000000ff
+#define A4XX_SP_GS_VPC_DST_REG_OUTLOC0__SHIFT                  0
+static inline uint32_t A4XX_SP_GS_VPC_DST_REG_OUTLOC0(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_VPC_DST_REG_OUTLOC0__SHIFT) & A4XX_SP_GS_VPC_DST_REG_OUTLOC0__MASK;
+}
+#define A4XX_SP_GS_VPC_DST_REG_OUTLOC1__MASK                   0x0000ff00
+#define A4XX_SP_GS_VPC_DST_REG_OUTLOC1__SHIFT                  8
+static inline uint32_t A4XX_SP_GS_VPC_DST_REG_OUTLOC1(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_VPC_DST_REG_OUTLOC1__SHIFT) & A4XX_SP_GS_VPC_DST_REG_OUTLOC1__MASK;
+}
+#define A4XX_SP_GS_VPC_DST_REG_OUTLOC2__MASK                   0x00ff0000
+#define A4XX_SP_GS_VPC_DST_REG_OUTLOC2__SHIFT                  16
+static inline uint32_t A4XX_SP_GS_VPC_DST_REG_OUTLOC2(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_VPC_DST_REG_OUTLOC2__SHIFT) & A4XX_SP_GS_VPC_DST_REG_OUTLOC2__MASK;
+}
+#define A4XX_SP_GS_VPC_DST_REG_OUTLOC3__MASK                   0xff000000
+#define A4XX_SP_GS_VPC_DST_REG_OUTLOC3__SHIFT                  24
+static inline uint32_t A4XX_SP_GS_VPC_DST_REG_OUTLOC3(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_VPC_DST_REG_OUTLOC3__SHIFT) & A4XX_SP_GS_VPC_DST_REG_OUTLOC3__MASK;
+}
+
 #define REG_A4XX_SP_GS_OBJ_OFFSET_REG                          0x0000235b
 #define A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK      0x01ff0000
 #define A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT     16
@@ -1693,6 +1867,18 @@ static inline uint32_t A4XX_VFD_CONTROL_3_REGID_VTXCNT(uint32_t val)
 {
        return ((val) << A4XX_VFD_CONTROL_3_REGID_VTXCNT__SHIFT) & A4XX_VFD_CONTROL_3_REGID_VTXCNT__MASK;
 }
+#define A4XX_VFD_CONTROL_3_REGID_TESSX__MASK                   0x00ff0000
+#define A4XX_VFD_CONTROL_3_REGID_TESSX__SHIFT                  16
+static inline uint32_t A4XX_VFD_CONTROL_3_REGID_TESSX(uint32_t val)
+{
+       return ((val) << A4XX_VFD_CONTROL_3_REGID_TESSX__SHIFT) & A4XX_VFD_CONTROL_3_REGID_TESSX__MASK;
+}
+#define A4XX_VFD_CONTROL_3_REGID_TESSY__MASK                   0xff000000
+#define A4XX_VFD_CONTROL_3_REGID_TESSY__SHIFT                  24
+static inline uint32_t A4XX_VFD_CONTROL_3_REGID_TESSY(uint32_t val)
+{
+       return ((val) << A4XX_VFD_CONTROL_3_REGID_TESSY__SHIFT) & A4XX_VFD_CONTROL_3_REGID_TESSY__MASK;
+}
 
 #define REG_A4XX_VFD_CONTROL_4                                 0x00002204
 
@@ -2489,6 +2675,8 @@ static inline uint32_t A4XX_UNKNOWN_20F7(float val)
 
 #define REG_A4XX_UNKNOWN_22D7                                  0x000022d7
 
+#define REG_A4XX_UNKNOWN_2352                                  0x00002352
+
 #define REG_A4XX_TEX_SAMP_0                                    0x00000000
 #define A4XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR                  0x00000001
 #define A4XX_TEX_SAMP_0_XY_MAG__MASK                           0x00000006
index 9562a1fa552b7319ce5b2af45f34377484db25d0..399a9e5281394a2d8f6c7562718e6d80cc050fbc 100644 (file)
@@ -8,15 +8,15 @@ http://github.com/freedreno/envytools/
 git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14895 bytes, from 2015-04-19 15:23:28)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  66709 bytes, from 2015-04-12 18:16:35)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  60633 bytes, from 2015-05-20 14:48:19)
-
-Copyright (C) 2013-2014 by the following authors:
+- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14968 bytes, from 2015-05-20 20:12:27)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  67120 bytes, from 2015-08-14 23:22:03)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  63785 bytes, from 2015-08-14 18:27:06)
+
+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
index bd5b23bf9041eff30c85f924a024b458452b83ba..41904fed135046d67afcf869a4bc3b30dfc17920 100644 (file)
@@ -8,13 +8,13 @@ http://github.com/freedreno/envytools/
 git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14895 bytes, from 2015-04-19 15:23:28)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  66709 bytes, from 2015-04-12 18:16:35)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  60633 bytes, from 2015-05-20 14:48:19)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14968 bytes, from 2015-05-20 20:12:27)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  67120 bytes, from 2015-08-14 23:22:03)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  63785 bytes, from 2015-08-14 18:27:06)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -67,7 +67,7 @@ enum vgt_event_type {
 
 enum pc_di_primtype {
        DI_PT_NONE = 0,
-       DI_PT_POINTLIST_A2XX = 1,
+       DI_PT_POINTLIST_PSIZE = 1,
        DI_PT_LINELIST = 2,
        DI_PT_LINESTRIP = 3,
        DI_PT_TRILIST = 4,
@@ -75,7 +75,7 @@ enum pc_di_primtype {
        DI_PT_TRISTRIP = 6,
        DI_PT_LINELOOP = 7,
        DI_PT_RECTLIST = 8,
-       DI_PT_POINTLIST_A3XX = 9,
+       DI_PT_POINTLIST = 9,
        DI_PT_LINE_ADJ = 10,
        DI_PT_LINESTRIP_ADJ = 11,
        DI_PT_TRI_ADJ = 12,
index 1f2561e2ff718f2f305b2a1891a26ab6cf1e3623..6edcd6f57e70d4da4170f419d62fc5669a36ef29 100644 (file)
 
 struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
 {
-       if (!msm_dsi || !msm_dsi->panel)
+       if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
                return NULL;
 
-       return (msm_dsi->panel_flags & MIPI_DSI_MODE_VIDEO) ?
+       return (msm_dsi->device_flags & MIPI_DSI_MODE_VIDEO) ?
                msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID] :
                msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID];
 }
@@ -74,19 +74,15 @@ static void dsi_destroy(struct msm_dsi *msm_dsi)
 
 static struct msm_dsi *dsi_init(struct platform_device *pdev)
 {
-       struct msm_dsi *msm_dsi = NULL;
+       struct msm_dsi *msm_dsi;
        int ret;
 
-       if (!pdev) {
-               ret = -ENXIO;
-               goto fail;
-       }
+       if (!pdev)
+               return ERR_PTR(-ENXIO);
 
        msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL);
-       if (!msm_dsi) {
-               ret = -ENOMEM;
-               goto fail;
-       }
+       if (!msm_dsi)
+               return ERR_PTR(-ENOMEM);
        DBG("dsi probed=%p", msm_dsi);
 
        msm_dsi->pdev = pdev;
@@ -95,24 +91,22 @@ static struct msm_dsi *dsi_init(struct platform_device *pdev)
        /* Init dsi host */
        ret = msm_dsi_host_init(msm_dsi);
        if (ret)
-               goto fail;
+               goto destroy_dsi;
 
        /* GET dsi PHY */
        ret = dsi_get_phy(msm_dsi);
        if (ret)
-               goto fail;
+               goto destroy_dsi;
 
        /* Register to dsi manager */
        ret = msm_dsi_manager_register(msm_dsi);
        if (ret)
-               goto fail;
+               goto destroy_dsi;
 
        return msm_dsi;
 
-fail:
-       if (msm_dsi)
-               dsi_destroy(msm_dsi);
-
+destroy_dsi:
+       dsi_destroy(msm_dsi);
        return ERR_PTR(ret);
 }
 
@@ -196,6 +190,7 @@ 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;
+       struct drm_bridge *ext_bridge;
        int ret, i;
 
        if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] ||
@@ -223,10 +218,25 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
                msm_dsi->encoders[i] = encoders[i];
        }
 
-       msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id);
+       /*
+        * check if the dsi encoder output is connected to a panel or an
+        * external bridge. We create a connector only if we're connected to a
+        * drm_panel device. When we're connected to an external bridge, we
+        * assume that the drm_bridge driver will create the connector itself.
+        */
+       ext_bridge = msm_dsi_host_get_bridge(msm_dsi->host);
+
+       if (ext_bridge)
+               msm_dsi->connector =
+                       msm_dsi_manager_ext_bridge_init(msm_dsi->id);
+       else
+               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);
+               dev_err(dev->dev,
+                       "failed to create dsi connector: %d\n", ret);
                msm_dsi->connector = NULL;
                goto fail;
        }
@@ -242,10 +252,12 @@ fail:
                        msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
                        msm_dsi->bridge = NULL;
                }
-               if (msm_dsi->connector) {
+
+               /* don't destroy connector if we didn't make it */
+               if (msm_dsi->connector && !msm_dsi->external_bridge)
                        msm_dsi->connector->funcs->destroy(msm_dsi->connector);
-                       msm_dsi->connector = NULL;
-               }
+
+               msm_dsi->connector = NULL;
        }
 
        return ret;
index 92d697de4858360495e24b50430eddc2d38fea83..5f5a3732cdf6c732a0aa1a7b584be22469993d91 100644 (file)
 #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
-
 enum msm_dsi_phy_type {
        MSM_DSI_PHY_28NM_HPM,
        MSM_DSI_PHY_28NM_LP,
+       MSM_DSI_PHY_20NM,
        MSM_DSI_PHY_MAX
 };
 
@@ -65,13 +54,21 @@ struct msm_dsi {
        struct drm_device *dev;
        struct platform_device *pdev;
 
+       /* connector managed by us when we're connected to a drm_panel */
        struct drm_connector *connector;
+       /* internal dsi bridge attached to MDP interface */
        struct drm_bridge *bridge;
 
        struct mipi_dsi_host *host;
        struct msm_dsi_phy *phy;
+
+       /*
+        * panel/external_bridge connected to dsi bridge output, only one of the
+        * two can be valid at a time
+        */
        struct drm_panel *panel;
-       unsigned long panel_flags;
+       struct drm_bridge *external_bridge;
+       unsigned long device_flags;
 
        struct device *phy_dev;
        bool phy_enabled;
@@ -86,6 +83,7 @@ struct msm_dsi {
 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);
+struct drm_connector *msm_dsi_manager_ext_bridge_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);
@@ -96,6 +94,11 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
 void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
 
 /* msm dsi */
+static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
+{
+       return msm_dsi->panel || msm_dsi->external_bridge;
+}
+
 struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
 
 /* dsi pll */
@@ -106,6 +109,8 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
 void msm_dsi_pll_destroy(struct msm_dsi_pll *pll);
 int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
        struct clk **byte_clk_provider, struct clk **pixel_clk_provider);
+void msm_dsi_pll_save_state(struct msm_dsi_pll *pll);
+int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll);
 #else
 static inline struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
                         enum msm_dsi_phy_type type, int id) {
@@ -119,6 +124,13 @@ static inline int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
 {
        return -ENODEV;
 }
+static inline void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
+{
+}
+static inline int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
+{
+       return 0;
+}
 #endif
 
 /* dsi host */
@@ -140,6 +152,7 @@ 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);
+struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
 int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer);
 void msm_dsi_host_unregister(struct mipi_dsi_host *host);
 int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
@@ -153,9 +166,9 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi);
 struct msm_dsi_phy;
 void msm_dsi_phy_driver_register(void);
 void msm_dsi_phy_driver_unregister(void);
-int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
+int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
        const unsigned long bit_rate, const unsigned long esc_rate);
-int msm_dsi_phy_disable(struct msm_dsi_phy *phy);
+void 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);
 struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy);
index 9791ea04bcbcf632a01a2bf978e0cfd0672eb05f..1d2e32f0817b590f902d33692c2b12d8530e1003 100644 (file)
@@ -8,17 +8,17 @@ 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            (  20915 bytes, from 2015-03-24 22:05:22)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2352 bytes, from 2015-04-12 15:02:42)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  35083 bytes, from 2015-04-12 15:04:03)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  22094 bytes, from 2015-05-12 12:45:23)
-- /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           (  29012 bytes, from 2015-05-12 12:45:23)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-12 12:45:23)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2576 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  36021 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  26057 bytes, from 2015-08-14 21:47:57)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  29154 bytes, from 2015-08-10 21:25:43)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-20 20:03:14)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -382,6 +382,11 @@ static inline uint32_t DSI_TRIG_CTRL_STREAM(uint32_t val)
 #define REG_DSI_TRIG_DMA                                       0x0000008c
 
 #define REG_DSI_DLN0_PHY_ERR                                   0x000000b0
+#define DSI_DLN0_PHY_ERR_DLN0_ERR_ESC                          0x00000001
+#define DSI_DLN0_PHY_ERR_DLN0_ERR_SYNC_ESC                     0x00000010
+#define DSI_DLN0_PHY_ERR_DLN0_ERR_CONTROL                      0x00000100
+#define DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP0               0x00001000
+#define DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP1               0x00010000
 
 #define REG_DSI_TIMEOUT_STATUS                                 0x000000bc
 
@@ -435,6 +440,9 @@ static inline uint32_t DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(enum dsi_lane_swap val)
 #define REG_DSI_PHY_RESET                                      0x00000128
 #define DSI_PHY_RESET_RESET                                    0x00000001
 
+#define REG_DSI_T_CLK_PRE_EXTEND                               0x0000017c
+#define DSI_T_CLK_PRE_EXTEND_INC_BY_2_BYTECLK                  0x00000001
+
 #define REG_DSI_RDBK_DATA_CTRL                                 0x000001d0
 #define DSI_RDBK_DATA_CTRL_COUNT__MASK                         0x00ff0000
 #define DSI_RDBK_DATA_CTRL_COUNT__SHIFT                                16
@@ -830,6 +838,7 @@ static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(uint32_t val)
 #define REG_DSI_28nm_PHY_BIST_CTRL_5                           0x000001c8
 
 #define REG_DSI_28nm_PHY_GLBL_TEST_CTRL                                0x000001d4
+#define DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL              0x00000001
 
 #define REG_DSI_28nm_PHY_LDO_CNTRL                             0x000001dc
 
@@ -994,5 +1003,185 @@ static inline uint32_t DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(uint32_t val)
 
 #define REG_DSI_28nm_PHY_PLL_CTRL_54                           0x000000d4
 
+static inline uint32_t REG_DSI_20nm_PHY_LN(uint32_t i0) { return 0x00000000 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_20nm_PHY_LN_CFG_0(uint32_t i0) { return 0x00000000 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_20nm_PHY_LN_CFG_1(uint32_t i0) { return 0x00000004 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_20nm_PHY_LN_CFG_2(uint32_t i0) { return 0x00000008 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_20nm_PHY_LN_CFG_3(uint32_t i0) { return 0x0000000c + 0x40*i0; }
+
+static inline uint32_t REG_DSI_20nm_PHY_LN_CFG_4(uint32_t i0) { return 0x00000010 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_20nm_PHY_LN_TEST_DATAPATH(uint32_t i0) { return 0x00000014 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_20nm_PHY_LN_DEBUG_SEL(uint32_t i0) { return 0x00000018 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_20nm_PHY_LN_TEST_STR_0(uint32_t i0) { return 0x0000001c + 0x40*i0; }
+
+static inline uint32_t REG_DSI_20nm_PHY_LN_TEST_STR_1(uint32_t i0) { return 0x00000020 + 0x40*i0; }
+
+#define REG_DSI_20nm_PHY_LNCK_CFG_0                            0x00000100
+
+#define REG_DSI_20nm_PHY_LNCK_CFG_1                            0x00000104
+
+#define REG_DSI_20nm_PHY_LNCK_CFG_2                            0x00000108
+
+#define REG_DSI_20nm_PHY_LNCK_CFG_3                            0x0000010c
+
+#define REG_DSI_20nm_PHY_LNCK_CFG_4                            0x00000110
+
+#define REG_DSI_20nm_PHY_LNCK_TEST_DATAPATH                    0x00000114
+
+#define REG_DSI_20nm_PHY_LNCK_DEBUG_SEL                                0x00000118
+
+#define REG_DSI_20nm_PHY_LNCK_TEST_STR0                                0x0000011c
+
+#define REG_DSI_20nm_PHY_LNCK_TEST_STR1                                0x00000120
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_0                         0x00000140
+#define DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO__MASK              0x000000ff
+#define DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT             0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO__MASK;
+}
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_1                         0x00000144
+#define DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK             0x000000ff
+#define DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT            0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK;
+}
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_2                         0x00000148
+#define DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK           0x000000ff
+#define DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT          0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK;
+}
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_3                         0x0000014c
+#define DSI_20nm_PHY_TIMING_CTRL_3_CLK_ZERO_8                  0x00000001
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_4                         0x00000150
+#define DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT__MASK               0x000000ff
+#define DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT              0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT__MASK;
+}
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_5                         0x00000154
+#define DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO__MASK               0x000000ff
+#define DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT              0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO__MASK;
+}
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_6                         0x00000158
+#define DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE__MASK            0x000000ff
+#define DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT           0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE__MASK;
+}
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_7                         0x0000015c
+#define DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL__MASK              0x000000ff
+#define DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT             0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL__MASK;
+}
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_8                         0x00000160
+#define DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST__MASK               0x000000ff
+#define DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST__SHIFT              0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST__MASK;
+}
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_9                         0x00000164
+#define DSI_20nm_PHY_TIMING_CTRL_9_TA_GO__MASK                 0x00000007
+#define DSI_20nm_PHY_TIMING_CTRL_9_TA_GO__SHIFT                        0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_9_TA_GO(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_9_TA_GO__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_9_TA_GO__MASK;
+}
+#define DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE__MASK               0x00000070
+#define DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE__SHIFT              4
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE__MASK;
+}
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_10                                0x00000168
+#define DSI_20nm_PHY_TIMING_CTRL_10_TA_GET__MASK               0x00000007
+#define DSI_20nm_PHY_TIMING_CTRL_10_TA_GET__SHIFT              0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_10_TA_GET(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_10_TA_GET__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_10_TA_GET__MASK;
+}
+
+#define REG_DSI_20nm_PHY_TIMING_CTRL_11                                0x0000016c
+#define DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK            0x000000ff
+#define DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT           0
+static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD(uint32_t val)
+{
+       return ((val) << DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK;
+}
+
+#define REG_DSI_20nm_PHY_CTRL_0                                        0x00000170
+
+#define REG_DSI_20nm_PHY_CTRL_1                                        0x00000174
+
+#define REG_DSI_20nm_PHY_CTRL_2                                        0x00000178
+
+#define REG_DSI_20nm_PHY_CTRL_3                                        0x0000017c
+
+#define REG_DSI_20nm_PHY_CTRL_4                                        0x00000180
+
+#define REG_DSI_20nm_PHY_STRENGTH_0                            0x00000184
+
+#define REG_DSI_20nm_PHY_STRENGTH_1                            0x00000188
+
+#define REG_DSI_20nm_PHY_BIST_CTRL_0                           0x000001b4
+
+#define REG_DSI_20nm_PHY_BIST_CTRL_1                           0x000001b8
+
+#define REG_DSI_20nm_PHY_BIST_CTRL_2                           0x000001bc
+
+#define REG_DSI_20nm_PHY_BIST_CTRL_3                           0x000001c0
+
+#define REG_DSI_20nm_PHY_BIST_CTRL_4                           0x000001c4
+
+#define REG_DSI_20nm_PHY_BIST_CTRL_5                           0x000001c8
+
+#define REG_DSI_20nm_PHY_GLBL_TEST_CTRL                                0x000001d4
+#define DSI_20nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL              0x00000001
+
+#define REG_DSI_20nm_PHY_LDO_CNTRL                             0x000001dc
+
+#define REG_DSI_20nm_PHY_REGULATOR_CTRL_0                      0x00000000
+
+#define REG_DSI_20nm_PHY_REGULATOR_CTRL_1                      0x00000004
+
+#define REG_DSI_20nm_PHY_REGULATOR_CTRL_2                      0x00000008
+
+#define REG_DSI_20nm_PHY_REGULATOR_CTRL_3                      0x0000000c
+
+#define REG_DSI_20nm_PHY_REGULATOR_CTRL_4                      0x00000010
+
+#define REG_DSI_20nm_PHY_REGULATOR_CTRL_5                      0x00000014
+
+#define REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG                 0x00000018
+
 
 #endif /* DSI_XML */
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
new file mode 100644 (file)
index 0000000..5872d5e
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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_cfg.h"
+
+/* DSI v2 has not been supported by now */
+static const struct msm_dsi_config dsi_v2_cfg = {
+       .io_offset = 0,
+};
+
+static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = {
+       .io_offset = DSI_6G_REG_SHIFT,
+       .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},
+               },
+       },
+};
+
+static const struct msm_dsi_config msm8916_dsi_cfg = {
+       .io_offset = DSI_6G_REG_SHIFT,
+       .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 const struct msm_dsi_config msm8994_dsi_cfg = {
+       .io_offset = DSI_6G_REG_SHIFT,
+       .reg_cfg = {
+               .num = 7,
+               .regs = {
+                       {"gdsc", -1, -1, -1, -1},
+                       {"vdda", 1250000, 1250000, 100000, 100},
+                       {"vddio", 1800000, 1800000, 100000, 100},
+                       {"vcca", 1000000, 1000000, 10000, 100},
+                       {"vdd", 1800000, 1800000, 100000, 100},
+                       {"lab_reg", -1, -1, -1, -1},
+                       {"ibb_reg", -1, -1, -1, -1},
+               },
+       }
+};
+
+static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = {
+       {MSM_DSI_VER_MAJOR_V2, U32_MAX, &dsi_v2_cfg},
+       {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_0,
+                                               &msm8974_apq8084_dsi_cfg},
+       {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_1,
+                                               &msm8974_apq8084_dsi_cfg},
+       {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_1_1,
+                                               &msm8974_apq8084_dsi_cfg},
+       {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_2,
+                                               &msm8974_apq8084_dsi_cfg},
+       {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3, &msm8994_dsi_cfg},
+       {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3_1, &msm8916_dsi_cfg},
+};
+
+const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor)
+{
+       const struct msm_dsi_cfg_handler *cfg_hnd = NULL;
+       int i;
+
+       for (i = ARRAY_SIZE(dsi_cfg_handlers) - 1; i >= 0; i--) {
+               if ((dsi_cfg_handlers[i].major == major) &&
+                       (dsi_cfg_handlers[i].minor == minor)) {
+                       cfg_hnd = &dsi_cfg_handlers[i];
+                       break;
+               }
+       }
+
+       return cfg_hnd;
+}
+
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
new file mode 100644 (file)
index 0000000..4cf8872
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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 __MSM_DSI_CFG_H__
+#define __MSM_DSI_CFG_H__
+
+#include "dsi.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      0x10030000
+#define MSM_DSI_6G_VER_MINOR_V1_3_1    0x10030001
+
+#define DSI_6G_REG_SHIFT       4
+
+struct msm_dsi_config {
+       u32 io_offset;
+       struct dsi_reg_config reg_cfg;
+};
+
+struct msm_dsi_cfg_handler {
+       u32 major;
+       u32 minor;
+       const struct msm_dsi_config *cfg;
+};
+
+const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor);
+
+#endif /* __MSM_DSI_CFG_H__ */
+
index de04009233035f1d69474933a0406a2ff46bd249..8d82973fe9db72479fe1219abd0b1c8dd0a40f6d 100644 (file)
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_graph.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
-
-struct dsi_config {
-       u32 major;
-       u32 minor;
-       u32 io_offset;
-       struct dsi_reg_config reg_cfg;
-};
-
-static const struct dsi_config dsi_cfgs[] = {
-       {MSM_DSI_VER_MAJOR_V2, 0, 0, {0,} },
-       { /* 8974 v1 */
-               .major = MSM_DSI_VER_MAJOR_6G,
-               .minor = MSM_DSI_6G_VER_MINOR_V1_0,
-               .io_offset = DSI_6G_REG_SHIFT,
-               .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,
-               .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,
-               .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,
-               .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,
-               .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},
-                       },
-               },
-       },
-};
+#include "dsi_cfg.h"
 
 static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
 {
@@ -194,7 +106,7 @@ struct msm_dsi_host {
        struct gpio_desc *disp_en_gpio;
        struct gpio_desc *te_gpio;
 
-       const struct dsi_config *cfg;
+       const struct msm_dsi_cfg_handler *cfg_hnd;
 
        struct completion dma_comp;
        struct completion video_comp;
@@ -212,8 +124,8 @@ struct msm_dsi_host {
 
        struct drm_display_mode *mode;
 
-       /* Panel info */
-       struct device_node *panel_node;
+       /* connected device info */
+       struct device_node *device_node;
        unsigned int channel;
        unsigned int lanes;
        enum mipi_dsi_pixel_format format;
@@ -239,61 +151,58 @@ static u32 dsi_get_bpp(const enum mipi_dsi_pixel_format fmt)
 
 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);
+       return msm_readl(msm_host->ctrl_base + 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);
+       msm_writel(data, msm_host->ctrl_base + 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)
+static const struct msm_dsi_cfg_handler *dsi_get_config(
+                                               struct msm_dsi_host *msm_host)
 {
-       const struct dsi_config *cfg;
+       const struct msm_dsi_cfg_handler *cfg_hnd = NULL;
        struct regulator *gdsc_reg;
-       int i, ret;
+       int ret;
        u32 major = 0, minor = 0;
 
        gdsc_reg = regulator_get(&msm_host->pdev->dev, "gdsc");
        if (IS_ERR(gdsc_reg)) {
                pr_err("%s: cannot get gdsc\n", __func__);
-               goto fail;
+               goto exit;
        }
        ret = regulator_enable(gdsc_reg);
        if (ret) {
                pr_err("%s: unable to enable gdsc\n", __func__);
-               regulator_put(gdsc_reg);
-               goto fail;
+               goto put_gdsc;
        }
        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;
+               goto disable_gdsc;
        }
 
        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;
+               goto disable_clks;
        }
 
-       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);
+       cfg_hnd = msm_dsi_cfg_get(major, minor);
 
-fail:
-       return NULL;
+       DBG("%s: Version %x:%x\n", __func__, major, minor);
+
+disable_clks:
+       clk_disable_unprepare(msm_host->ahb_clk);
+disable_gdsc:
+       regulator_disable(gdsc_reg);
+put_gdsc:
+       regulator_put(gdsc_reg);
+exit:
+       return cfg_hnd;
 }
 
 static inline struct msm_dsi_host *to_msm_dsi_host(struct mipi_dsi_host *host)
@@ -304,8 +213,8 @@ static inline struct msm_dsi_host *to_msm_dsi_host(struct mipi_dsi_host *host)
 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;
+       const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs;
+       int num = msm_host->cfg_hnd->cfg->reg_cfg.num;
        int i;
 
        DBG("");
@@ -320,8 +229,8 @@ static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host)
 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;
+       const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs;
+       int num = msm_host->cfg_hnd->cfg->reg_cfg.num;
        int ret, i;
 
        DBG("");
@@ -354,8 +263,8 @@ fail:
 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;
+       const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs;
+       int num = msm_host->cfg_hnd->cfg->reg_cfg.num;
        int i, ret;
 
        for (i = 0; i < num; i++)
@@ -697,6 +606,7 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable,
 {
        u32 flags = msm_host->mode_flags;
        enum mipi_dsi_pixel_format mipi_fmt = msm_host->format;
+       const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
        u32 data = 0;
 
        if (!enable) {
@@ -750,8 +660,8 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable,
        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))
+       if ((cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) &&
+               (cfg_hnd->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);
 
@@ -1257,7 +1167,11 @@ static void dsi_dln0_phy_err(struct msm_dsi_host *msm_host)
 
        status = dsi_read(msm_host, REG_DSI_DLN0_PHY_ERR);
 
-       if (status) {
+       if (status & (DSI_DLN0_PHY_ERR_DLN0_ERR_ESC |
+                       DSI_DLN0_PHY_ERR_DLN0_ERR_SYNC_ESC |
+                       DSI_DLN0_PHY_ERR_DLN0_ERR_CONTROL |
+                       DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP0 |
+                       DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP1)) {
                dsi_write(msm_host, REG_DSI_DLN0_PHY_ERR, status);
                msm_host->err_work_state |= DSI_ERR_STATE_DLN0_PHY;
        }
@@ -1359,7 +1273,8 @@ static int dsi_host_init_panel_gpios(struct msm_dsi_host *msm_host,
                return PTR_ERR(msm_host->disp_en_gpio);
        }
 
-       msm_host->te_gpio = devm_gpiod_get(panel_device, "disp-te", GPIOD_IN);
+       msm_host->te_gpio = devm_gpiod_get_optional(panel_device, "disp-te",
+                                                               GPIOD_IN);
        if (IS_ERR(msm_host->te_gpio)) {
                DBG("cannot get disp-te-gpios %ld", PTR_ERR(msm_host->te_gpio));
                return PTR_ERR(msm_host->te_gpio);
@@ -1379,7 +1294,7 @@ static int dsi_host_attach(struct mipi_dsi_host *host,
        msm_host->format = dsi->format;
        msm_host->mode_flags = dsi->mode_flags;
 
-       msm_host->panel_node = dsi->dev.of_node;
+       WARN_ON(dsi->dev.of_node != msm_host->device_node);
 
        /* Some gpios defined in panel DT need to be controlled by host */
        ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev);
@@ -1398,7 +1313,7 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
 {
        struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
 
-       msm_host->panel_node = NULL;
+       msm_host->device_node = NULL;
 
        DBG("id=%d", msm_host->id);
        if (msm_host->dev)
@@ -1429,6 +1344,48 @@ static struct mipi_dsi_host_ops dsi_host_ops = {
        .transfer = dsi_host_transfer,
 };
 
+static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
+{
+       struct device *dev = &msm_host->pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct device_node *endpoint, *device_node;
+       int ret;
+
+       ret = of_property_read_u32(np, "qcom,dsi-host-index", &msm_host->id);
+       if (ret) {
+               dev_err(dev, "%s: host index not specified, ret=%d\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       /*
+        * Get the first endpoint node. In our case, dsi has one output port
+        * to which the panel is connected. Don't return an error if a port
+        * isn't defined. It's possible that there is nothing connected to
+        * the dsi output.
+        */
+       endpoint = of_graph_get_next_endpoint(np, NULL);
+       if (!endpoint) {
+               dev_dbg(dev, "%s: no endpoint\n", __func__);
+               return 0;
+       }
+
+       /* Get panel node from the output port's endpoint data */
+       device_node = of_graph_get_remote_port_parent(endpoint);
+       if (!device_node) {
+               dev_err(dev, "%s: no valid device\n", __func__);
+               of_node_put(endpoint);
+               return -ENODEV;
+       }
+
+       of_node_put(endpoint);
+       of_node_put(device_node);
+
+       msm_host->device_node = device_node;
+
+       return 0;
+}
+
 int msm_dsi_host_init(struct msm_dsi *msm_dsi)
 {
        struct msm_dsi_host *msm_host = NULL;
@@ -1443,15 +1400,13 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
                goto fail;
        }
 
-       ret = of_property_read_u32(pdev->dev.of_node,
-                               "qcom,dsi-host-index", &msm_host->id);
+       msm_host->pdev = pdev;
+
+       ret = dsi_host_parse_dt(msm_host);
        if (ret) {
-               dev_err(&pdev->dev,
-                       "%s: host index not specified, ret=%d\n",
-                       __func__, ret);
+               pr_err("%s: failed to parse dt\n", __func__);
                goto fail;
        }
-       msm_host->pdev = pdev;
 
        ret = dsi_clk_init(msm_host);
        if (ret) {
@@ -1466,13 +1421,16 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
                goto fail;
        }
 
-       msm_host->cfg = dsi_get_config(msm_host);
-       if (!msm_host->cfg) {
+       msm_host->cfg_hnd = dsi_get_config(msm_host);
+       if (!msm_host->cfg_hnd) {
                ret = -EINVAL;
                pr_err("%s: get config failed\n", __func__);
                goto fail;
        }
 
+       /* fixup base address by io offset */
+       msm_host->ctrl_base += msm_host->cfg_hnd->cfg->io_offset;
+
        ret = dsi_regulator_init(msm_host);
        if (ret) {
                pr_err("%s: regulator init failed\n", __func__);
@@ -1559,7 +1517,6 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
 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 */
@@ -1577,14 +1534,13 @@ int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
                 * It makes sure panel is connected when fbcon detects
                 * connector status and gets the proper display mode to
                 * create framebuffer.
+                * Don't try to defer if there is nothing connected to the dsi
+                * output
                 */
-               if (check_defer) {
-                       node = of_get_child_by_name(msm_host->pdev->dev.of_node,
-                                                       "panel");
-                       if (node) {
-                               if (!of_drm_find_panel(node))
+               if (check_defer && msm_host->device_node) {
+                       if (!of_drm_find_panel(msm_host->device_node))
+                               if (!of_drm_find_bridge(msm_host->device_node))
                                        return -EPROBE_DEFER;
-                       }
                }
        }
 
@@ -1663,6 +1619,7 @@ 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);
+       const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
        int data_byte, rx_byte, dlen, end;
        int short_response, diff, pkt_size, ret = 0;
        char cmd;
@@ -1704,8 +1661,8 @@ int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
                        return -EINVAL;
                }
 
-               if ((msm_host->cfg->major == MSM_DSI_VER_MAJOR_6G) &&
-                       (msm_host->cfg->minor >= MSM_DSI_6G_VER_MINOR_V1_1)) {
+               if ((cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) &&
+                       (cfg_hnd->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);
@@ -1919,6 +1876,13 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host)
                goto fail_disable_reg;
        }
 
+       ret = pinctrl_pm_select_default_state(&msm_host->pdev->dev);
+       if (ret) {
+               pr_err("%s: failed to set pinctrl default state, %d\n",
+                       __func__, ret);
+               goto fail_disable_clk;
+       }
+
        dsi_timing_setup(msm_host);
        dsi_sw_reset(msm_host);
        dsi_ctrl_config(msm_host, true, clk_pre, clk_post);
@@ -1931,6 +1895,8 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host)
 
        return 0;
 
+fail_disable_clk:
+       dsi_clk_ctrl(msm_host, 0);
 fail_disable_reg:
        dsi_host_regulator_disable(msm_host);
 unlock_ret:
@@ -1953,6 +1919,8 @@ int msm_dsi_host_power_off(struct mipi_dsi_host *host)
        if (msm_host->disp_en_gpio)
                gpiod_set_value(msm_host->disp_en_gpio, 0);
 
+       pinctrl_pm_select_sleep_state(&msm_host->pdev->dev);
+
        msm_dsi_manager_phy_disable(msm_host->id);
 
        dsi_clk_ctrl(msm_host, 0);
@@ -1993,10 +1961,16 @@ struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
        struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
        struct drm_panel *panel;
 
-       panel = of_drm_find_panel(msm_host->panel_node);
+       panel = of_drm_find_panel(msm_host->device_node);
        if (panel_flags)
                        *panel_flags = msm_host->mode_flags;
 
        return panel;
 }
 
+struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       return of_drm_find_bridge(msm_host->device_node);
+}
index 87ac6612b6f85a574f7f7f246c11888afaa08e7a..0455ff75074adbf638661976b289a91120d23560 100644 (file)
 #include "msm_kms.h"
 #include "dsi.h"
 
+#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_manager {
        struct msm_dsi *dsi[DSI_MAX];
 
-       bool is_dual_panel;
+       bool is_dual_dsi;
        bool is_sync_needed;
-       int master_panel_id;
+       int master_dsi_link_id;
 };
 
 static struct msm_dsi_manager msm_dsim_glb;
 
-#define IS_DUAL_PANEL()                (msm_dsim_glb.is_dual_panel)
+#define IS_DUAL_DSI()          (msm_dsim_glb.is_dual_dsi)
 #define IS_SYNC_NEEDED()       (msm_dsim_glb.is_sync_needed)
-#define IS_MASTER_PANEL(id)    (msm_dsim_glb.master_panel_id == id)
+#define IS_MASTER_DSI_LINK(id) (msm_dsim_glb.master_dsi_link_id == id)
 
 static inline struct msm_dsi *dsi_mgr_get_dsi(int id)
 {
@@ -38,23 +50,23 @@ 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)
+static int dsi_mgr_parse_dual_dsi(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
+       /* We assume 2 dsi nodes have the same information of dual-dsi 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_dsi)
+               msm_dsim->is_dual_dsi = of_property_read_bool(
+                                               np, "qcom,dual-dsi-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_dual_dsi) {
+               if (of_property_read_bool(np, "qcom,master-dsi"))
+                       msm_dsim->master_dsi_link_id = id;
                if (!msm_dsim->is_sync_needed)
                        msm_dsim->is_sync_needed = of_property_read_bool(
-                                       np, "qcom,sync-dual-panel");
+                                       np, "qcom,sync-dual-dsi");
        }
 
        return 0;
@@ -68,7 +80,7 @@ static int dsi_mgr_host_register(int id)
        struct msm_dsi_pll *src_pll;
        int ret;
 
-       if (!IS_DUAL_PANEL()) {
+       if (!IS_DUAL_DSI()) {
                ret = msm_dsi_host_register(msm_dsi->host, true);
                if (ret)
                        return ret;
@@ -78,9 +90,9 @@ static int dsi_mgr_host_register(int id)
        } else if (!other_dsi) {
                ret = 0;
        } else {
-               struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ?
+               struct msm_dsi *mdsi = IS_MASTER_DSI_LINK(id) ?
                                        msm_dsi : other_dsi;
-               struct msm_dsi *sdsi = IS_MASTER_PANEL(id) ?
+               struct msm_dsi *sdsi = IS_MASTER_DSI_LINK(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
@@ -144,28 +156,28 @@ static enum drm_connector_status dsi_mgr_connector_detect(
        DBG("id=%d", id);
        if (!msm_dsi->panel) {
                msm_dsi->panel = msm_dsi_host_get_panel(msm_dsi->host,
-                                               &msm_dsi->panel_flags);
+                                               &msm_dsi->device_flags);
 
                /* There is only 1 panel in the global panel list
-                * for dual panel mode. Therefore slave dsi should get
+                * for dual DSI 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)
+               if (!msm_dsi->panel && IS_DUAL_DSI() &&
+                       !IS_MASTER_DSI_LINK(id) && other_dsi)
                        msm_dsi->panel = msm_dsi_host_get_panel(
                                        other_dsi->host, NULL);
 
-               if (msm_dsi->panel && IS_DUAL_PANEL())
+               if (msm_dsi->panel && IS_DUAL_DSI())
                        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
+               /* Set split display info to kms once dual DSI panel is
+                * connected to both hosts.
                 */
-               if (msm_dsi->panel && IS_DUAL_PANEL() &&
+               if (msm_dsi->panel && IS_DUAL_DSI() &&
                        other_dsi && other_dsi->panel) {
-                       bool cmd_mode = !(msm_dsi->panel_flags &
+                       bool cmd_mode = !(msm_dsi->device_flags &
                                                MIPI_DSI_MODE_VIDEO);
                        struct drm_encoder *encoder = msm_dsi_get_encoder(
                                        dsi_mgr_get_dsi(DSI_ENCODER_MASTER));
@@ -176,7 +188,7 @@ static enum drm_connector_status dsi_mgr_connector_detect(
                                kms->funcs->set_split_display(kms, encoder,
                                                        slave_enc, cmd_mode);
                        else
-                               pr_err("mdp does not support dual panel\n");
+                               pr_err("mdp does not support dual DSI\n");
                }
        }
 
@@ -273,7 +285,7 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
        if (!num)
                return 0;
 
-       if (IS_DUAL_PANEL()) {
+       if (IS_DUAL_DSI()) {
                /* report half resolution to user */
                dsi_dual_connector_fix_modes(connector);
                ret = dsi_dual_connector_tile_init(connector, id);
@@ -328,11 +340,12 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
        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();
+       bool is_dual_dsi = IS_DUAL_DSI();
        int ret;
 
        DBG("id=%d", id);
-       if (!panel || (is_dual_panel && (DSI_1 == id)))
+       if (!msm_dsi_device_connected(msm_dsi) ||
+                       (is_dual_dsi && (DSI_1 == id)))
                return;
 
        ret = msm_dsi_host_power_on(host);
@@ -341,7 +354,7 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
                goto host_on_fail;
        }
 
-       if (is_dual_panel && msm_dsi1) {
+       if (is_dual_dsi && msm_dsi1) {
                ret = msm_dsi_host_power_on(msm_dsi1->host);
                if (ret) {
                        pr_err("%s: power on host1 failed, %d\n",
@@ -353,10 +366,13 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
        /* 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;
+       if (panel) {
+               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);
@@ -365,7 +381,7 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
                goto host_en_fail;
        }
 
-       if (is_dual_panel && msm_dsi1) {
+       if (is_dual_dsi && msm_dsi1) {
                ret = msm_dsi_host_enable(msm_dsi1->host);
                if (ret) {
                        pr_err("%s: enable host1 failed, %d\n", __func__, ret);
@@ -373,23 +389,27 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
                }
        }
 
-       ret = drm_panel_enable(panel);
-       if (ret) {
-               pr_err("%s: enable panel %d failed, %d\n", __func__, id, ret);
-               goto panel_en_fail;
+       if (panel) {
+               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)
+       if (is_dual_dsi && msm_dsi1)
                msm_dsi_host_disable(msm_dsi1->host);
 host1_en_fail:
        msm_dsi_host_disable(host);
 host_en_fail:
-       drm_panel_unprepare(panel);
+       if (panel)
+               drm_panel_unprepare(panel);
 panel_prep_fail:
-       if (is_dual_panel && msm_dsi1)
+       if (is_dual_dsi && msm_dsi1)
                msm_dsi_host_power_off(msm_dsi1->host);
 host1_on_fail:
        msm_dsi_host_power_off(host);
@@ -414,37 +434,44 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
        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();
+       bool is_dual_dsi = IS_DUAL_DSI();
        int ret;
 
        DBG("id=%d", id);
 
-       if (!panel || (is_dual_panel && (DSI_1 == id)))
+       if (!msm_dsi_device_connected(msm_dsi) ||
+                       (is_dual_dsi && (DSI_1 == id)))
                return;
 
-       ret = drm_panel_disable(panel);
-       if (ret)
-               pr_err("%s: Panel %d OFF failed, %d\n", __func__, id, ret);
+       if (panel) {
+               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) {
+       if (is_dual_dsi && 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);
+       if (panel) {
+               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) {
+       if (is_dual_dsi && msm_dsi1) {
                ret = msm_dsi_host_power_off(msm_dsi1->host);
                if (ret)
                        pr_err("%s: host1 power off failed, %d\n",
@@ -460,7 +487,7 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *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();
+       bool is_dual_dsi = IS_DUAL_DSI();
 
        DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
                        mode->base.id, mode->name,
@@ -471,11 +498,11 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
                        mode->vsync_end, mode->vtotal,
                        mode->type, mode->flags);
 
-       if (is_dual_panel && (DSI_1 == id))
+       if (is_dual_dsi && (DSI_1 == id))
                return;
 
        msm_dsi_host_set_display_mode(host, adjusted_mode);
-       if (is_dual_panel && other_dsi)
+       if (is_dual_dsi && other_dsi)
                msm_dsi_host_set_display_mode(other_dsi->host, adjusted_mode);
 }
 
@@ -503,7 +530,7 @@ static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
        .mode_set = dsi_mgr_bridge_mode_set,
 };
 
-/* initialize connector */
+/* initialize connector when we're connected to a drm_panel */
 struct drm_connector *msm_dsi_manager_connector_init(u8 id)
 {
        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
@@ -588,6 +615,53 @@ fail:
        return ERR_PTR(ret);
 }
 
+struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct drm_device *dev = msm_dsi->dev;
+       struct drm_encoder *encoder;
+       struct drm_bridge *int_bridge, *ext_bridge;
+       struct drm_connector *connector;
+       struct list_head *connector_list;
+
+       int_bridge = msm_dsi->bridge;
+       ext_bridge = msm_dsi->external_bridge =
+                       msm_dsi_host_get_bridge(msm_dsi->host);
+
+       /*
+        * HACK: we may not know the external DSI bridge device's mode
+        * flags here. We'll get to know them only when the device
+        * attaches to the dsi host. For now, assume the bridge supports
+        * DSI video mode
+        */
+       encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
+
+       /* link the internal dsi bridge to the external bridge */
+       int_bridge->next = ext_bridge;
+       /* set the external bridge's encoder as dsi's encoder */
+       ext_bridge->encoder = encoder;
+
+       drm_bridge_attach(dev, ext_bridge);
+
+       /*
+        * we need the drm_connector created by the external bridge
+        * driver (or someone else) to feed it to our driver's
+        * priv->connector[] list, mainly for msm_fbdev_init()
+        */
+       connector_list = &dev->mode_config.connector_list;
+
+       list_for_each_entry(connector, connector_list, head) {
+               int i;
+
+               for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+                       if (connector->encoder_ids[i] == encoder->base.id)
+                               return connector;
+               }
+       }
+
+       return ERR_PTR(-ENODEV);
+}
+
 void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
 {
 }
@@ -598,12 +672,29 @@ int msm_dsi_manager_phy_enable(int id,
 {
        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
        struct msm_dsi_phy *phy = msm_dsi->phy;
+       int src_pll_id = IS_DUAL_DSI() ? DSI_CLOCK_MASTER : id;
+       struct msm_dsi_pll *pll = msm_dsi_phy_get_pll(msm_dsi->phy);
        int ret;
 
-       ret = msm_dsi_phy_enable(phy, IS_DUAL_PANEL(), bit_rate, esc_rate);
+       ret = msm_dsi_phy_enable(phy, src_pll_id, bit_rate, esc_rate);
        if (ret)
                return ret;
 
+       /*
+        * Reset DSI PHY silently changes its PLL registers to reset status,
+        * which will confuse clock driver and result in wrong output rate of
+        * link clocks. Restore PLL status if its PLL is being used as clock
+        * source.
+        */
+       if (!IS_DUAL_DSI() || (id == DSI_CLOCK_MASTER)) {
+               ret = msm_dsi_pll_restore_state(pll);
+               if (ret) {
+                       pr_err("%s: failed to restore pll state\n", __func__);
+                       msm_dsi_phy_disable(phy);
+                       return ret;
+               }
+       }
+
        msm_dsi->phy_enabled = true;
        msm_dsi_phy_get_clk_pre_post(phy, clk_pre, clk_post);
 
@@ -616,13 +707,18 @@ void msm_dsi_manager_phy_disable(int 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;
+       struct msm_dsi_pll *pll = msm_dsi_phy_get_pll(msm_dsi->phy);
+
+       /* Save PLL status if it is a clock source */
+       if (!IS_DUAL_DSI() || (id == DSI_CLOCK_MASTER))
+               msm_dsi_pll_save_state(pll);
 
        /* 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 (IS_DUAL_DSI() && mdsi && sdsi) {
                if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
                        msm_dsi_phy_disable(sdsi->phy);
                        msm_dsi_phy_disable(mdsi->phy);
@@ -713,9 +809,9 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
 
        msm_dsim->dsi[id] = msm_dsi;
 
-       ret = dsi_mgr_parse_dual_panel(msm_dsi->pdev->dev.of_node, id);
+       ret = dsi_mgr_parse_dual_dsi(msm_dsi->pdev->dev.of_node, id);
        if (ret) {
-               pr_err("%s: failed to parse dual panel info\n", __func__);
+               pr_err("%s: failed to parse dual DSI info\n", __func__);
                goto fail;
        }
 
index 728152f3ef48b6b2fbfabe5185b4f3dfa39d697b..5de505e627beb0eeb7f74d529eadc3ad3cdb6af3 100644 (file)
@@ -8,19 +8,19 @@ 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            (  20915 bytes, from 2015-03-24 22:05:22)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2352 bytes, from 2015-04-12 15:02:42)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  35083 bytes, from 2015-04-12 15:04:03)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  22094 bytes, from 2015-05-12 12:45:23)
-- /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           (  29012 bytes, from 2015-05-12 12:45:23)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-12 12:45:23)
-
-Copyright (C) 2013-2014 by the following authors:
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2576 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  36021 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  26057 bytes, from 2015-08-14 21:47:57)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  29154 bytes, from 2015-08-10 21:25:43)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-20 20:03:14)
+
+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
similarity index 54%
rename from drivers/gpu/drm/msm/dsi/dsi_phy.c
rename to drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index 2d3b33ce1cc54f68ac117699c39bba64e3ce2087..401ff58d6893e704b943a7c53f033b93e53abd4c 100644 (file)
  */
 
 #include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
 
-#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_phy_ops {
-       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);
-};
-
-struct dsi_phy_cfg {
-       enum msm_dsi_phy_type type;
-       struct dsi_reg_config reg_cfg;
-       struct dsi_phy_ops ops;
-};
-
-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 {
-       struct platform_device *pdev;
-       void __iomem *base;
-       void __iomem *reg_base;
-       int id;
-
-       struct clk *ahb_clk;
-       struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX];
-
-       struct dsi_dphy_timing timing;
-       const struct dsi_phy_cfg *cfg;
-
-       struct msm_dsi_pll *pll;
-};
-
-static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
-{
-       struct regulator_bulk_data *s = phy->supplies;
-       const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
-       struct device *dev = &phy->pdev->dev;
-       int num = phy->cfg->reg_cfg.num;
-       int i, ret;
-
-       for (i = 0; i < num; i++)
-               s[i].supply = regs[i].name;
-
-       ret = devm_regulator_bulk_get(&phy->pdev->dev, num, s);
-       if (ret < 0) {
-               dev_err(dev, "%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) {
-                               dev_err(dev,
-                                       "regulator %d set voltage failed, %d\n",
-                                       i, ret);
-                               return ret;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
-{
-       struct regulator_bulk_data *s = phy->supplies;
-       const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
-       int num = phy->cfg->reg_cfg.num;
-       int i;
-
-       DBG("");
-       for (i = num - 1; i >= 0; i--)
-               if (regs[i].disable_load >= 0)
-                       regulator_set_load(s[i].consumer,
-                                               regs[i].disable_load);
-
-       regulator_bulk_disable(num, s);
-}
-
-static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
-{
-       struct regulator_bulk_data *s = phy->supplies;
-       const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
-       struct device *dev = &phy->pdev->dev;
-       int num = phy->cfg->reg_cfg.num;
-       int ret, i;
-
-       DBG("");
-       for (i = 0; i < num; i++) {
-               if (regs[i].enable_load >= 0) {
-                       ret = regulator_set_load(s[i].consumer,
-                                                       regs[i].enable_load);
-                       if (ret < 0) {
-                               dev_err(dev,
-                                       "regulator %d set op mode failed, %d\n",
-                                       i, ret);
-                               goto fail;
-                       }
-               }
-       }
-
-       ret = regulator_bulk_enable(num, s);
-       if (ret < 0) {
-               dev_err(dev, "regulator enable failed, %d\n", ret);
-               goto fail;
-       }
-
-       return 0;
-
-fail:
-       for (i--; i >= 0; i--)
-               regulator_set_load(s[i].consumer, regs[i].disable_load);
-       return ret;
-}
+#include "dsi_phy.h"
 
 #define S_DIV_ROUND_UP(n, d)   \
        (((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
@@ -156,6 +22,7 @@ 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))
@@ -164,7 +31,7 @@ static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
                return max_t(s32, min_result, v);
 }
 
-static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing,
+static void dsi_dphy_timing_calc_clk_zero(struct msm_dsi_dphy_timing *timing,
                                        s32 ui, s32 coeff, s32 pcnt)
 {
        s32 tmax, tmin, clk_z;
@@ -186,7 +53,7 @@ static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing,
        timing->clk_zero = clk_z + 8 - temp;
 }
 
-static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
+int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
        const unsigned long bit_rate, const unsigned long esc_rate)
 {
        s32 ui, lpx;
@@ -256,9 +123,8 @@ static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
        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;
+               temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false);
                timing->clk_pre = temp >> 1;
-               temp = (2 * tmax - tmin) * pcnt2;
        } else {
                timing->clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false);
        }
@@ -276,130 +142,119 @@ static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
        return 0;
 }
 
-static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
+void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
+                               u32 bit_mask)
 {
-       void __iomem *base = phy->reg_base;
+       int phy_id = phy->id;
+       u32 val;
 
-       if (!enable) {
-               dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
+       if ((phy_id >= DSI_MAX) || (pll_id >= DSI_MAX))
                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);
+       val = dsi_phy_read(phy->base + reg);
+
+       if (phy->cfg->src_pll_truthtable[phy_id][pll_id])
+               dsi_phy_write(phy->base + reg, val | bit_mask);
+       else
+               dsi_phy_write(phy->base + reg, val & (~bit_mask));
 }
 
-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)
+static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
 {
-       struct dsi_dphy_timing *timing = &phy->timing;
-       int i;
-       void __iomem *base = phy->base;
+       struct regulator_bulk_data *s = phy->supplies;
+       const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
+       struct device *dev = &phy->pdev->dev;
+       int num = phy->cfg->reg_cfg.num;
+       int i, ret;
 
-       DBG("");
+       for (i = 0; i < num; i++)
+               s[i].supply = regs[i].name;
 
-       if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
-               pr_err("%s: D-PHY timing calculation failed\n", __func__);
-               return -EINVAL;
+       ret = devm_regulator_bulk_get(dev, num, s);
+       if (ret < 0) {
+               dev_err(dev, "%s: failed to init regulator, ret=%d\n",
+                                               __func__, ret);
+               return ret;
        }
 
-       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);
+       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) {
+                               dev_err(dev,
+                                       "regulator %d set voltage failed, %d\n",
+                                       i, ret);
+                               return ret;
+                       }
+               }
        }
-       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);
+       return 0;
+}
 
-       dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
+static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
+{
+       struct regulator_bulk_data *s = phy->supplies;
+       const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
+       int num = phy->cfg->reg_cfg.num;
+       int i;
 
-       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);
+       DBG("");
+       for (i = num - 1; i >= 0; i--)
+               if (regs[i].disable_load >= 0)
+                       regulator_set_load(s[i].consumer, regs[i].disable_load);
 
-       return 0;
+       regulator_bulk_disable(num, s);
 }
 
-static int dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
+static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
 {
-       dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0);
-       dsi_28nm_phy_regulator_ctrl(phy, false);
+       struct regulator_bulk_data *s = phy->supplies;
+       const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
+       struct device *dev = &phy->pdev->dev;
+       int num = phy->cfg->reg_cfg.num;
+       int ret, i;
 
-       /*
-        * Wait for the registers writes to complete in order to
-        * ensure that the phy is completely disabled
-        */
-       wmb();
+       DBG("");
+       for (i = 0; i < num; i++) {
+               if (regs[i].enable_load >= 0) {
+                       ret = regulator_set_load(s[i].consumer,
+                                                       regs[i].enable_load);
+                       if (ret < 0) {
+                               dev_err(dev,
+                                       "regulator %d set op mode failed, %d\n",
+                                       i, ret);
+                               goto fail;
+                       }
+               }
+       }
+
+       ret = regulator_bulk_enable(num, s);
+       if (ret < 0) {
+               dev_err(dev, "regulator enable failed, %d\n", ret);
+               goto fail;
+       }
 
        return 0;
+
+fail:
+       for (i--; i >= 0; i--)
+               regulator_set_load(s[i].consumer, regs[i].disable_load);
+       return ret;
 }
 
 static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
 {
+       struct device *dev = &phy->pdev->dev;
        int ret;
 
-       pm_runtime_get_sync(&phy->pdev->dev);
+       pm_runtime_get_sync(dev);
 
        ret = clk_prepare_enable(phy->ahb_clk);
        if (ret) {
-               pr_err("%s: can't enable ahb clk, %d\n", __func__, ret);
-               pm_runtime_put_sync(&phy->pdev->dev);
+               dev_err(dev, "%s: can't enable ahb clk, %d\n", __func__, ret);
+               pm_runtime_put_sync(dev);
        }
 
        return ret;
@@ -411,92 +266,74 @@ static void dsi_phy_disable_resource(struct msm_dsi_phy *phy)
        pm_runtime_put_sync(&phy->pdev->dev);
 }
 
-static const struct dsi_phy_cfg dsi_phy_cfgs[MSM_DSI_PHY_MAX] = {
-       [MSM_DSI_PHY_28NM_HPM] = {
-               .type = MSM_DSI_PHY_28NM_HPM,
-               .reg_cfg = {
-                       .num = 1,
-                       .regs = {
-                               {"vddio", 1800000, 1800000, 100000, 100},
-                       },
-               },
-               .ops = {
-                       .enable = dsi_28nm_phy_enable,
-                       .disable = dsi_28nm_phy_disable,
-               }
-       },
-       [MSM_DSI_PHY_28NM_LP] = {
-               .type = MSM_DSI_PHY_28NM_LP,
-               .reg_cfg = {
-                       .num = 1,
-                       .regs = {
-                               {"vddio", 1800000, 1800000, 100000, 100},
-                       },
-               },
-               .ops = {
-                       .enable = dsi_28nm_phy_enable,
-                       .disable = dsi_28nm_phy_disable,
-               }
-       },
-};
-
 static const struct of_device_id dsi_phy_dt_match[] = {
+#ifdef CONFIG_DRM_MSM_DSI_28NM_PHY
        { .compatible = "qcom,dsi-phy-28nm-hpm",
-         .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_HPM],},
+         .data = &dsi_phy_28nm_hpm_cfgs },
        { .compatible = "qcom,dsi-phy-28nm-lp",
-         .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_LP],},
+         .data = &dsi_phy_28nm_lp_cfgs },
+#endif
+#ifdef CONFIG_DRM_MSM_DSI_20NM_PHY
+       { .compatible = "qcom,dsi-phy-20nm",
+         .data = &dsi_phy_20nm_cfgs },
+#endif
        {}
 };
 
 static int dsi_phy_driver_probe(struct platform_device *pdev)
 {
        struct msm_dsi_phy *phy;
+       struct device *dev = &pdev->dev;
        const struct of_device_id *match;
        int ret;
 
-       phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+       phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
        if (!phy)
                return -ENOMEM;
 
-       match = of_match_node(dsi_phy_dt_match, pdev->dev.of_node);
+       match = of_match_node(dsi_phy_dt_match, dev->of_node);
        if (!match)
                return -ENODEV;
 
        phy->cfg = match->data;
        phy->pdev = pdev;
 
-       ret = of_property_read_u32(pdev->dev.of_node,
+       ret = of_property_read_u32(dev->of_node,
                                "qcom,dsi-phy-index", &phy->id);
        if (ret) {
-               dev_err(&pdev->dev,
-                       "%s: PHY index not specified, ret=%d\n",
+               dev_err(dev, "%s: PHY index not specified, %d\n",
                        __func__, ret);
                goto fail;
        }
 
+       phy->regulator_ldo_mode = of_property_read_bool(dev->of_node,
+                               "qcom,dsi-phy-regulator-ldo-mode");
+
        phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
        if (IS_ERR(phy->base)) {
-               dev_err(&pdev->dev, "%s: failed to map phy base\n", __func__);
+               dev_err(dev, "%s: failed to map phy base\n", __func__);
                ret = -ENOMEM;
                goto fail;
        }
-       phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG");
+
+       phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator",
+                               "DSI_PHY_REG");
        if (IS_ERR(phy->reg_base)) {
-               dev_err(&pdev->dev,
-                       "%s: failed to map phy regulator base\n", __func__);
+               dev_err(dev, "%s: failed to map phy regulator base\n",
+                       __func__);
                ret = -ENOMEM;
                goto fail;
        }
 
        ret = dsi_phy_regulator_init(phy);
        if (ret) {
-               dev_err(&pdev->dev, "%s: failed to init regulator\n", __func__);
+               dev_err(dev, "%s: failed to init regulator\n", __func__);
                goto fail;
        }
 
-       phy->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
+       phy->ahb_clk = devm_clk_get(dev, "iface_clk");
        if (IS_ERR(phy->ahb_clk)) {
-               pr_err("%s: Unable to get ahb clk\n", __func__);
+               dev_err(dev, "%s: Unable to get ahb clk\n", __func__);
                ret = PTR_ERR(phy->ahb_clk);
                goto fail;
        }
@@ -510,7 +347,7 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
 
        phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
        if (!phy->pll)
-               dev_info(&pdev->dev,
+               dev_info(dev,
                        "%s: pll init failed, need separate pll clk driver\n",
                        __func__);
 
@@ -557,9 +394,10 @@ void __exit msm_dsi_phy_driver_unregister(void)
        platform_driver_unregister(&dsi_phy_platform_driver);
 }
 
-int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
+int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
        const unsigned long bit_rate, const unsigned long esc_rate)
 {
+       struct device *dev = &phy->pdev->dev;
        int ret;
 
        if (!phy || !phy->cfg->ops.enable)
@@ -567,30 +405,37 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
 
        ret = dsi_phy_regulator_enable(phy);
        if (ret) {
-               dev_err(&phy->pdev->dev, "%s: regulator enable failed, %d\n",
+               dev_err(dev, "%s: regulator enable failed, %d\n",
                        __func__, ret);
                return ret;
        }
 
-       return phy->cfg->ops.enable(phy, is_dual_panel, bit_rate, esc_rate);
+       ret = phy->cfg->ops.enable(phy, src_pll_id, bit_rate, esc_rate);
+       if (ret) {
+               dev_err(dev, "%s: phy enable failed, %d\n", __func__, ret);
+               dsi_phy_regulator_disable(phy);
+               return ret;
+       }
+
+       return 0;
 }
 
-int msm_dsi_phy_disable(struct msm_dsi_phy *phy)
+void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
 {
        if (!phy || !phy->cfg->ops.disable)
-               return -EINVAL;
+               return;
 
        phy->cfg->ops.disable(phy);
-       dsi_phy_regulator_disable(phy);
 
-       return 0;
+       dsi_phy_regulator_disable(phy);
 }
 
 void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
-       u32 *clk_pre, u32 *clk_post)
+                                       u32 *clk_pre, u32 *clk_post)
 {
        if (!phy)
                return;
+
        if (clk_pre)
                *clk_pre = phy->timing.clk_pre;
        if (clk_post)
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
new file mode 100644 (file)
index 0000000..0456b25
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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_PHY_H__
+#define __DSI_PHY_H__
+
+#include <linux/regulator/consumer.h>
+
+#include "dsi.h"
+
+#define dsi_phy_read(offset) msm_readl((offset))
+#define dsi_phy_write(offset, data) msm_writel((data), (offset))
+
+struct msm_dsi_phy_ops {
+       int (*enable)(struct msm_dsi_phy *phy, int src_pll_id,
+               const unsigned long bit_rate, const unsigned long esc_rate);
+       void (*disable)(struct msm_dsi_phy *phy);
+};
+
+struct msm_dsi_phy_cfg {
+       enum msm_dsi_phy_type type;
+       struct dsi_reg_config reg_cfg;
+       struct msm_dsi_phy_ops ops;
+
+       /*
+        * Each cell {phy_id, pll_id} of the truth table indicates
+        * if the source PLL selection bit should be set for each PHY.
+        * Fill default H/W values in illegal cells, eg. cell {0, 1}.
+        */
+       bool src_pll_truthtable[DSI_MAX][DSI_MAX];
+};
+
+extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs;
+
+struct msm_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 {
+       struct platform_device *pdev;
+       void __iomem *base;
+       void __iomem *reg_base;
+       int id;
+
+       struct clk *ahb_clk;
+       struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX];
+
+       struct msm_dsi_dphy_timing timing;
+       const struct msm_dsi_phy_cfg *cfg;
+
+       bool regulator_ldo_mode;
+
+       struct msm_dsi_pll *pll;
+};
+
+/*
+ * PHY internal functions
+ */
+int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
+       const unsigned long bit_rate, const unsigned long esc_rate);
+void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
+                               u32 bit_mask);
+
+#endif /* __DSI_PHY_H__ */
+
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c
new file mode 100644 (file)
index 0000000..2e9ba11
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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_phy.h"
+#include "dsi.xml.h"
+
+static void dsi_20nm_dphy_set_timing(struct msm_dsi_phy *phy,
+               struct msm_dsi_dphy_timing *timing)
+{
+       void __iomem *base = phy->base;
+
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_0,
+               DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_1,
+               DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_2,
+               DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
+       if (timing->clk_zero & BIT(8))
+               dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_3,
+                       DSI_20nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_4,
+               DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_5,
+               DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_6,
+               DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_7,
+               DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_8,
+               DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_9,
+               DSI_20nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
+               DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_10,
+               DSI_20nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
+       dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_11,
+               DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
+}
+
+static void dsi_20nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
+{
+       void __iomem *base = phy->reg_base;
+
+       if (!enable) {
+               dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
+               return;
+       }
+
+       if (phy->regulator_ldo_mode) {
+               dsi_phy_write(phy->base + REG_DSI_20nm_PHY_LDO_CNTRL, 0x1d);
+               return;
+       }
+
+       /* non LDO mode */
+       dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_1, 0x03);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_2, 0x03);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_3, 0x00);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_4, 0x20);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG, 0x01);
+       dsi_phy_write(phy->base + REG_DSI_20nm_PHY_LDO_CNTRL, 0x00);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_0, 0x03);
+}
+
+static int dsi_20nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+               const unsigned long bit_rate, const unsigned long esc_rate)
+{
+       struct msm_dsi_dphy_timing *timing = &phy->timing;
+       int i;
+       void __iomem *base = phy->base;
+       u32 cfg_4[4] = {0x20, 0x40, 0x20, 0x00};
+
+       DBG("");
+
+       if (msm_dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
+               dev_err(&phy->pdev->dev,
+                       "%s: D-PHY timing calculation failed\n", __func__);
+               return -EINVAL;
+       }
+
+       dsi_20nm_phy_regulator_ctrl(phy, true);
+
+       dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_0, 0xff);
+
+       msm_dsi_phy_set_src_pll(phy, src_pll_id,
+                               REG_DSI_20nm_PHY_GLBL_TEST_CTRL,
+                               DSI_20nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);
+
+       for (i = 0; i < 4; i++) {
+               dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_3(i),
+                                                       (i >> 1) * 0x40);
+               dsi_phy_write(base + REG_DSI_20nm_PHY_LN_TEST_STR_0(i), 0x01);
+               dsi_phy_write(base + REG_DSI_20nm_PHY_LN_TEST_STR_1(i), 0x46);
+               dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_0(i), 0x02);
+               dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_1(i), 0xa0);
+               dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_4(i), cfg_4[i]);
+       }
+
+       dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_3, 0x80);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_TEST_STR0, 0x01);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_TEST_STR1, 0x46);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_0, 0x00);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_1, 0xa0);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_2, 0x00);
+       dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_4, 0x00);
+
+       dsi_20nm_dphy_set_timing(phy, timing);
+
+       dsi_phy_write(base + REG_DSI_20nm_PHY_CTRL_1, 0x00);
+
+       dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_1, 0x06);
+
+       /* make sure everything is written before enable */
+       wmb();
+       dsi_phy_write(base + REG_DSI_20nm_PHY_CTRL_0, 0x7f);
+
+       return 0;
+}
+
+static void dsi_20nm_phy_disable(struct msm_dsi_phy *phy)
+{
+       dsi_phy_write(phy->base + REG_DSI_20nm_PHY_CTRL_0, 0);
+       dsi_20nm_phy_regulator_ctrl(phy, false);
+}
+
+const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs = {
+       .type = MSM_DSI_PHY_20NM,
+       .src_pll_truthtable = { {false, true}, {false, true} },
+       .reg_cfg = {
+               .num = 2,
+               .regs = {
+                       {"vddio", 1800000, 1800000, 100000, 100},
+                       {"vcca", 1000000, 1000000, 10000, 100},
+               },
+       },
+       .ops = {
+               .enable = dsi_20nm_phy_enable,
+               .disable = dsi_20nm_phy_disable,
+       }
+};
+
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c
new file mode 100644 (file)
index 0000000..f1a7c7b
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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_phy.h"
+#include "dsi.xml.h"
+
+static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy,
+               struct msm_dsi_dphy_timing *timing)
+{
+       void __iomem *base = phy->base;
+
+       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));
+}
+
+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, int src_pll_id,
+               const unsigned long bit_rate, const unsigned long esc_rate)
+{
+       struct msm_dsi_dphy_timing *timing = &phy->timing;
+       int i;
+       void __iomem *base = phy->base;
+
+       DBG("");
+
+       if (msm_dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
+               dev_err(&phy->pdev->dev,
+                       "%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_28nm_dphy_set_timing(phy, timing);
+
+       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);
+
+       msm_dsi_phy_set_src_pll(phy, src_pll_id,
+                               REG_DSI_28nm_PHY_GLBL_TEST_CTRL,
+                               DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);
+
+       return 0;
+}
+
+static void 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();
+}
+
+const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = {
+       .type = MSM_DSI_PHY_28NM_HPM,
+       .src_pll_truthtable = { {true, true}, {false, true} },
+       .reg_cfg = {
+               .num = 1,
+               .regs = {
+                       {"vddio", 1800000, 1800000, 100000, 100},
+               },
+       },
+       .ops = {
+               .enable = dsi_28nm_phy_enable,
+               .disable = dsi_28nm_phy_disable,
+       },
+};
+
+const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = {
+       .type = MSM_DSI_PHY_28NM_LP,
+       .src_pll_truthtable = { {true, true}, {true, true} },
+       .reg_cfg = {
+               .num = 1,
+               .regs = {
+                       {"vddio", 1800000, 1800000, 100000, 100},
+               },
+       },
+       .ops = {
+               .enable = dsi_28nm_phy_enable,
+               .disable = dsi_28nm_phy_disable,
+       },
+};
+
index 509376fdd1120e883519178048c9831aca63130d..5104fc9f9a5398e71d4869264f49f3a74c801b84 100644 (file)
@@ -72,31 +72,14 @@ long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw,
 int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw)
 {
        struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
-       int ret;
-
-       /*
-        * Certain PLLs need to update the same VCO rate and registers
-        * after resume in suspend/resume scenario.
-        */
-       if (pll->restore_state) {
-               ret = pll->restore_state(pll);
-               if (ret)
-                       goto error;
-       }
 
-       ret = dsi_pll_enable(pll);
-
-error:
-       return ret;
+       return dsi_pll_enable(pll);
 }
 
 void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw)
 {
        struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
 
-       if (pll->save_state)
-               pll->save_state(pll);
-
        dsi_pll_disable(pll);
 }
 
@@ -134,6 +117,29 @@ void msm_dsi_pll_destroy(struct msm_dsi_pll *pll)
                pll->destroy(pll);
 }
 
+void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
+{
+       if (pll->save_state) {
+               pll->save_state(pll);
+               pll->state_saved = true;
+       }
+}
+
+int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
+{
+       int ret;
+
+       if (pll->restore_state && pll->state_saved) {
+               ret = pll->restore_state(pll);
+               if (ret)
+                       return ret;
+
+               pll->state_saved = false;
+       }
+
+       return 0;
+}
+
 struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
                        enum msm_dsi_phy_type type, int id)
 {
index 5a3bb241c039b7403ad1e9683281a71d4d4e21ba..063caa2c5740fe9462c6646f171d4f9422831eb4 100644 (file)
@@ -27,6 +27,7 @@ struct msm_dsi_pll {
 
        struct clk_hw   clk_hw;
        bool            pll_on;
+       bool            state_saved;
 
        unsigned long   min_rate;
        unsigned long   max_rate;
@@ -82,8 +83,16 @@ void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev,
 /*
  * Initialization for Each PLL Type
  */
+#ifdef CONFIG_DRM_MSM_DSI_28NM_PHY
 struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device *pdev,
                                        enum msm_dsi_phy_type type, int id);
+#else
+static inline struct msm_dsi_pll *msm_dsi_pll_28nm_init(
+       struct platform_device *pdev, enum msm_dsi_phy_type type, int id)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif
 
 #endif /* __DSI_PLL_H__ */
 
index eb8ac3097ff501b19bea92c69ed73bf1caa988de..1912cfcca48c85eb4c788d0dda0366ae06371ba3 100644 (file)
@@ -465,26 +465,21 @@ static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll)
        void __iomem *base = pll_28nm->mmio;
        int ret;
 
-       if ((cached_state->vco_rate != 0) &&
-               (cached_state->vco_rate == __clk_get_rate(pll->clk_hw.clk))) {
-               ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
-                                               cached_state->vco_rate, 0);
-               if (ret) {
-                       dev_err(&pll_28nm->pdev->dev,
-                               "restore vco rate failed. ret=%d\n", ret);
-                       return ret;
-               }
-
-               pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
-                               cached_state->postdiv3);
-               pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
-                               cached_state->postdiv1);
-               pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
-                               cached_state->byte_mux);
-
-               cached_state->vco_rate = 0;
+       ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
+                                       cached_state->vco_rate, 0);
+       if (ret) {
+               dev_err(&pll_28nm->pdev->dev,
+                       "restore vco rate failed. ret=%d\n", ret);
+               return ret;
        }
 
+       pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
+                       cached_state->postdiv3);
+       pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
+                       cached_state->postdiv1);
+       pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
+                       cached_state->byte_mux);
+
        return 0;
 }
 
index 26f268e2dd3d944a56471a174506d21febc6e079..06cbddfc914fbd44ece12db2ac16fb81f4ec583a 100644 (file)
@@ -8,19 +8,19 @@ 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            (  20915 bytes, from 2015-03-24 22:05:22)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2352 bytes, from 2015-04-12 15:02:42)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  35083 bytes, from 2015-04-12 15:04:03)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  22094 bytes, from 2015-05-12 12:45:23)
-- /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           (  29012 bytes, from 2015-05-12 12:45:23)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-12 12:45:23)
-
-Copyright (C) 2013 by the following authors:
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2576 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  36021 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  26057 bytes, from 2015-08-14 21:47:57)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  29154 bytes, from 2015-08-10 21:25:43)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-20 20:03:14)
+
+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
index f9c71dceb5e296c89f93262baa3740e9c29e6ecb..bef1d65fe28c80b16f391997751dbf72f964fe47 100644 (file)
@@ -8,17 +8,17 @@ 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            (  20915 bytes, from 2015-03-24 22:05:22)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2352 bytes, from 2015-04-12 15:02:42)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  35083 bytes, from 2015-04-12 15:04:03)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  22094 bytes, from 2015-05-12 12:45:23)
-- /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           (  29012 bytes, from 2015-05-12 12:45:23)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-12 12:45:23)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2576 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  36021 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  26057 bytes, from 2015-08-14 21:47:57)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  29154 bytes, from 2015-08-10 21:25:43)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-20 20:03:14)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index 7991069dd492ada6ce2eb5ef0df979fe9c1cd431..81200e9be3821c9c87db1a26d46318d133378ba8 100644 (file)
@@ -373,7 +373,7 @@ static int edp_gpio_config(struct edp_ctrl *ctrl)
        struct device *dev = &ctrl->pdev->dev;
        int ret;
 
-       ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd");
+       ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd", GPIOD_IN);
        if (IS_ERR(ctrl->panel_hpd_gpio)) {
                ret = PTR_ERR(ctrl->panel_hpd_gpio);
                ctrl->panel_hpd_gpio = NULL;
@@ -381,13 +381,7 @@ static int edp_gpio_config(struct edp_ctrl *ctrl)
                return ret;
        }
 
-       ret = gpiod_direction_input(ctrl->panel_hpd_gpio);
-       if (ret) {
-               pr_err("%s: Set direction for hpd failed, %d\n", __func__, ret);
-               return ret;
-       }
-
-       ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en");
+       ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en", GPIOD_OUT_LOW);
        if (IS_ERR(ctrl->panel_en_gpio)) {
                ret = PTR_ERR(ctrl->panel_en_gpio);
                ctrl->panel_en_gpio = NULL;
@@ -395,13 +389,6 @@ static int edp_gpio_config(struct edp_ctrl *ctrl)
                return ret;
        }
 
-       ret = gpiod_direction_output(ctrl->panel_en_gpio, 0);
-       if (ret) {
-               pr_err("%s: Set direction for panel_en failed, %d\n",
-                               __func__, ret);
-               return ret;
-       }
-
        DBG("gpio on");
 
        return 0;
index 814536202efe589f691f35c65fc603ddb053293c..101b324cdeeff8e269d62454f20ccff5b66a32bf 100644 (file)
@@ -22,7 +22,9 @@
 void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
 {
        uint32_t ctrl = 0;
+       unsigned long flags;
 
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
        if (power_on) {
                ctrl |= HDMI_CTRL_ENABLE;
                if (!hdmi->hdmi_mode) {
@@ -37,6 +39,7 @@ void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
        }
 
        hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
        DBG("HDMI Core: %s, HDMI_CTRL=0x%08x",
                        power_on ? "Enable" : "Disable", ctrl);
 }
@@ -51,6 +54,10 @@ static irqreturn_t hdmi_irq(int irq, void *dev_id)
        /* Process DDC: */
        hdmi_i2c_irq(hdmi->i2c);
 
+       /* Process HDCP: */
+       if (hdmi->hdcp_ctrl)
+               hdmi_hdcp_irq(hdmi->hdcp_ctrl);
+
        /* TODO audio.. */
 
        return IRQ_HANDLED;
@@ -60,6 +67,15 @@ static void hdmi_destroy(struct hdmi *hdmi)
 {
        struct hdmi_phy *phy = hdmi->phy;
 
+       /*
+        * at this point, hpd has been disabled,
+        * after flush workq, it's safe to deinit hdcp
+        */
+       if (hdmi->workq) {
+               flush_workqueue(hdmi->workq);
+               destroy_workqueue(hdmi->workq);
+       }
+       hdmi_hdcp_destroy(hdmi);
        if (phy)
                phy->funcs->destroy(phy);
 
@@ -77,6 +93,7 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
 {
        struct hdmi_platform_config *config = pdev->dev.platform_data;
        struct hdmi *hdmi = NULL;
+       struct resource *res;
        int i, ret;
 
        hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
@@ -87,18 +104,18 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
 
        hdmi->pdev = pdev;
        hdmi->config = config;
+       spin_lock_init(&hdmi->reg_lock);
 
        /* not sure about which phy maps to which msm.. probably I miss some */
-       if (config->phy_init)
+       if (config->phy_init) {
                hdmi->phy = config->phy_init(hdmi);
-       else
-               hdmi->phy = ERR_PTR(-ENXIO);
 
-       if (IS_ERR(hdmi->phy)) {
-               ret = PTR_ERR(hdmi->phy);
-               dev_err(&pdev->dev, "failed to load phy: %d\n", ret);
-               hdmi->phy = NULL;
-               goto fail;
+               if (IS_ERR(hdmi->phy)) {
+                       ret = PTR_ERR(hdmi->phy);
+                       dev_err(&pdev->dev, "failed to load phy: %d\n", ret);
+                       hdmi->phy = NULL;
+                       goto fail;
+               }
        }
 
        hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI");
@@ -107,6 +124,18 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
                goto fail;
        }
 
+       /* HDCP needs physical address of hdmi register */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+               config->mmio_name);
+       hdmi->mmio_phy_addr = res->start;
+
+       hdmi->qfprom_mmio = msm_ioremap(pdev,
+               config->qfprom_mmio_name, "HDMI_QFPROM");
+       if (IS_ERR(hdmi->qfprom_mmio)) {
+               dev_info(&pdev->dev, "can't find qfprom resource\n");
+               hdmi->qfprom_mmio = NULL;
+       }
+
        hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) *
                        config->hpd_reg_cnt, GFP_KERNEL);
        if (!hdmi->hpd_regs) {
@@ -189,6 +218,8 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
                hdmi->pwr_clks[i] = clk;
        }
 
+       hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
+
        hdmi->i2c = hdmi_i2c_init(hdmi);
        if (IS_ERR(hdmi->i2c)) {
                ret = PTR_ERR(hdmi->i2c);
@@ -197,6 +228,12 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
                goto fail;
        }
 
+       hdmi->hdcp_ctrl = hdmi_hdcp_init(hdmi);
+       if (IS_ERR(hdmi->hdcp_ctrl)) {
+               dev_warn(&pdev->dev, "failed to init hdcp: disabled\n");
+               hdmi->hdcp_ctrl = NULL;
+       }
+
        return hdmi;
 
 fail:
@@ -310,7 +347,7 @@ static const char *pwr_clk_names_8x74[] = {"extp_clk", "alt_iface_clk"};
 static const char *hpd_clk_names_8x74[] = {"iface_clk", "core_clk", "mdp_core_clk"};
 static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0};
 
-static struct hdmi_platform_config hdmi_tx_8074_config = {
+static struct hdmi_platform_config hdmi_tx_8974_config = {
                .phy_init = hdmi_phy_8x74_init,
                HDMI_CFG(pwr_reg, 8x74),
                HDMI_CFG(hpd_reg, 8x74),
@@ -330,9 +367,21 @@ static struct hdmi_platform_config hdmi_tx_8084_config = {
                .hpd_freq      = hpd_clk_freq_8x74,
 };
 
+static const char *hpd_reg_names_8x94[] = {};
+
+static struct hdmi_platform_config hdmi_tx_8994_config = {
+               .phy_init = NULL, /* nothing to do for this HDMI PHY 20nm */
+               HDMI_CFG(pwr_reg, 8x74),
+               HDMI_CFG(hpd_reg, 8x94),
+               HDMI_CFG(pwr_clk, 8x74),
+               HDMI_CFG(hpd_clk, 8x74),
+               .hpd_freq      = hpd_clk_freq_8x74,
+};
+
 static const struct of_device_id dt_match[] = {
+       { .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config },
        { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config },
-       { .compatible = "qcom,hdmi-tx-8074", .data = &hdmi_tx_8074_config },
+       { .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config },
        { .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },
        { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config },
        {}
@@ -347,8 +396,7 @@ static int get_gpio(struct device *dev, struct device_node *of_node, const char
                snprintf(name2, sizeof(name2), "%s-gpio", name);
                gpio = of_get_named_gpio(of_node, name2, 0);
                if (gpio < 0) {
-                       dev_err(dev, "failed to get gpio: %s (%d)\n",
-                                       name, gpio);
+                       DBG("failed to get gpio: %s (%d)", name, gpio);
                        gpio = -1;
                }
        }
@@ -376,6 +424,7 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
        }
 
        hdmi_cfg->mmio_name     = "core_physical";
+       hdmi_cfg->qfprom_mmio_name = "qfprom_physical";
        hdmi_cfg->ddc_clk_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk");
        hdmi_cfg->ddc_data_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-data");
        hdmi_cfg->hpd_gpio      = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd");
@@ -391,7 +440,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
        if (cpu_is_apq8064()) {
                static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
                config.phy_init      = hdmi_phy_8960_init;
-               config.mmio_name     = "hdmi_msm_hdmi_addr";
                config.hpd_reg_names = hpd_reg_names;
                config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
                config.hpd_clk_names = hpd_clk_names;
@@ -404,7 +452,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
        } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
                static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
                config.phy_init      = hdmi_phy_8960_init;
-               config.mmio_name     = "hdmi_msm_hdmi_addr";
                config.hpd_reg_names = hpd_reg_names;
                config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
                config.hpd_clk_names = hpd_clk_names;
@@ -419,7 +466,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
                                "8901_hdmi_mvs", "8901_mpp0"
                };
                config.phy_init      = hdmi_phy_8x60_init;
-               config.mmio_name     = "hdmi_msm_hdmi_addr";
                config.hpd_reg_names = hpd_reg_names;
                config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
                config.hpd_clk_names = hpd_clk_names;
@@ -430,6 +476,9 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
                config.mux_en_gpio   = -1;
                config.mux_sel_gpio  = -1;
        }
+       config.mmio_name     = "hdmi_msm_hdmi_addr";
+       config.qfprom_mmio_name = "hdmi_msm_qfprom_addr";
+
        hdmi_cfg = &config;
 #endif
        dev->platform_data = hdmi_cfg;
index 68fdfb3622a5f6d754ed0e9b9e851f8775e08977..d0e663192d01f6b3471f8ef578bc16a2e538cd10 100644 (file)
@@ -37,6 +37,8 @@ struct hdmi_audio {
        int rate;
 };
 
+struct hdmi_hdcp_ctrl;
+
 struct hdmi {
        struct drm_device *dev;
        struct platform_device *pdev;
@@ -51,6 +53,8 @@ struct hdmi {
        unsigned long int pixclock;
 
        void __iomem *mmio;
+       void __iomem *qfprom_mmio;
+       phys_addr_t mmio_phy_addr;
 
        struct regulator **hpd_regs;
        struct regulator **pwr_regs;
@@ -68,12 +72,25 @@ struct hdmi {
        bool hdmi_mode;               /* are we in hdmi mode? */
 
        int irq;
+       struct workqueue_struct *workq;
+
+       struct hdmi_hdcp_ctrl *hdcp_ctrl;
+
+       /*
+       * spinlock to protect registers shared by different execution
+       * REG_HDMI_CTRL
+       * REG_HDMI_DDC_ARBITRATION
+       * REG_HDMI_HDCP_INT_CTRL
+       * REG_HDMI_HPD_CTRL
+       */
+       spinlock_t reg_lock;
 };
 
 /* platform config data (ie. from DT, or pdata) */
 struct hdmi_platform_config {
        struct hdmi_phy *(*phy_init)(struct hdmi *hdmi);
        const char *mmio_name;
+       const char *qfprom_mmio_name;
 
        /* regulators that need to be on for hpd: */
        const char **hpd_reg_names;
@@ -109,6 +126,11 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
        return msm_readl(hdmi->mmio + reg);
 }
 
+static inline u32 hdmi_qfprom_read(struct hdmi *hdmi, u32 reg)
+{
+       return msm_readl(hdmi->qfprom_mmio + reg);
+}
+
 /*
  * The phy appears to be different, for example between 8960 and 8x60,
  * so split the phy related functions out and load the correct one at
@@ -117,7 +139,6 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
 
 struct hdmi_phy_funcs {
        void (*destroy)(struct hdmi_phy *phy);
-       void (*reset)(struct hdmi_phy *phy);
        void (*powerup)(struct hdmi_phy *phy, unsigned long int pixclock);
        void (*powerdown)(struct hdmi_phy *phy);
 };
@@ -163,4 +184,13 @@ void hdmi_i2c_irq(struct i2c_adapter *i2c);
 void hdmi_i2c_destroy(struct i2c_adapter *i2c);
 struct i2c_adapter *hdmi_i2c_init(struct hdmi *hdmi);
 
+/*
+ * hdcp
+ */
+struct hdmi_hdcp_ctrl *hdmi_hdcp_init(struct hdmi *hdmi);
+void hdmi_hdcp_destroy(struct hdmi *hdmi);
+void hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl);
+void hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl);
+void hdmi_hdcp_irq(struct hdmi_hdcp_ctrl *hdcp_ctrl);
+
 #endif /* __HDMI_CONNECTOR_H__ */
index e6f03480837132efb239c5f5ff99cd52eceffa12..0b1b5586ff35c348bf0b79d079036439f3a48bce 100644 (file)
@@ -8,17 +8,17 @@ 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            (  20915 bytes, from 2015-03-24 22:05:22)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2352 bytes, from 2015-04-12 15:02:42)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  35083 bytes, from 2015-04-12 15:04:03)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  22094 bytes, from 2015-05-12 12:45:23)
-- /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           (  29012 bytes, from 2015-05-12 12:45:23)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-12 12:45:23)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2576 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  36021 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  26057 bytes, from 2015-08-14 21:47:57)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  29154 bytes, from 2015-08-10 21:25:43)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-20 20:03:14)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -441,6 +441,12 @@ static inline uint32_t HDMI_DDC_REF_REFTIMER(uint32_t val)
 
 #define REG_HDMI_HDCP_SW_LOWER_AKSV                            0x00000288
 
+#define REG_HDMI_CEC_CTRL                                      0x0000028c
+
+#define REG_HDMI_CEC_WR_DATA                                   0x00000290
+
+#define REG_HDMI_CEC_CEC_RETRANSMIT                            0x00000294
+
 #define REG_HDMI_CEC_STATUS                                    0x00000298
 
 #define REG_HDMI_CEC_INT                                       0x0000029c
index 872485f601342963f341258f33da66b23460d442..df232e20c13e1cc0d49c2ff7b5dbd827f238d51d 100644 (file)
@@ -203,7 +203,6 @@ int hdmi_audio_update(struct hdmi *hdmi)
                audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
                audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
        } else {
-               hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
                acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_CONT;
                acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SEND;
                vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
index a7a1d8267cf000ad5164479e861c82f68d011e7d..92b69ae8caf9c41c9c6cb80249ed726faafde5f8 100644 (file)
@@ -100,8 +100,13 @@ static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
                hdmi_audio_update(hdmi);
        }
 
-       phy->funcs->powerup(phy, hdmi->pixclock);
+       if (phy)
+               phy->funcs->powerup(phy, hdmi->pixclock);
+
        hdmi_set_mode(hdmi, true);
+
+       if (hdmi->hdcp_ctrl)
+               hdmi_hdcp_on(hdmi->hdcp_ctrl);
 }
 
 static void hdmi_bridge_enable(struct drm_bridge *bridge)
@@ -118,9 +123,14 @@ static void hdmi_bridge_post_disable(struct drm_bridge *bridge)
        struct hdmi *hdmi = hdmi_bridge->hdmi;
        struct hdmi_phy *phy = hdmi->phy;
 
+       if (hdmi->hdcp_ctrl)
+               hdmi_hdcp_off(hdmi->hdcp_ctrl);
+
        DBG("power down");
        hdmi_set_mode(hdmi, false);
-       phy->funcs->powerdown(phy);
+
+       if (phy)
+               phy->funcs->powerdown(phy);
 
        if (hdmi->power_on) {
                power_off(bridge);
@@ -142,8 +152,6 @@ static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
 
        hdmi->pixclock = mode->clock * 1000;
 
-       hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
-
        hstart = mode->htotal - mode->hsync_start;
        hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
 
index 54aa93ff547337d6bee6aa55bb339956f4d2f750..a3b05ae52dae636d5a1a06fcfa646bc53474ccdf 100644 (file)
@@ -28,6 +28,55 @@ struct hdmi_connector {
 };
 #define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
 
+static void hdmi_phy_reset(struct hdmi *hdmi)
+{
+       unsigned int val;
+
+       val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
+
+       if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
+               /* pull low */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val & ~HDMI_PHY_CTRL_SW_RESET);
+       } else {
+               /* pull high */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val | HDMI_PHY_CTRL_SW_RESET);
+       }
+
+       if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
+               /* pull low */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
+       } else {
+               /* pull high */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val | HDMI_PHY_CTRL_SW_RESET_PLL);
+       }
+
+       msleep(100);
+
+       if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
+               /* pull high */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val | HDMI_PHY_CTRL_SW_RESET);
+       } else {
+               /* pull low */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val & ~HDMI_PHY_CTRL_SW_RESET);
+       }
+
+       if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
+               /* pull high */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val | HDMI_PHY_CTRL_SW_RESET_PLL);
+       } else {
+               /* pull low */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
+       }
+}
+
 static int gpio_config(struct hdmi *hdmi, bool on)
 {
        struct device *dev = &hdmi->pdev->dev;
@@ -35,21 +84,25 @@ static int gpio_config(struct hdmi *hdmi, bool on)
        int ret;
 
        if (on) {
-               ret = gpio_request(config->ddc_clk_gpio, "HDMI_DDC_CLK");
-               if (ret) {
-                       dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
-                               "HDMI_DDC_CLK", config->ddc_clk_gpio, ret);
-                       goto error1;
+               if (config->ddc_clk_gpio != -1) {
+                       ret = gpio_request(config->ddc_clk_gpio, "HDMI_DDC_CLK");
+                       if (ret) {
+                               dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
+                                       "HDMI_DDC_CLK", config->ddc_clk_gpio, ret);
+                               goto error1;
+                       }
+                       gpio_set_value_cansleep(config->ddc_clk_gpio, 1);
                }
-               gpio_set_value_cansleep(config->ddc_clk_gpio, 1);
 
-               ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
-               if (ret) {
-                       dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
-                               "HDMI_DDC_DATA", config->ddc_data_gpio, ret);
-                       goto error2;
+               if (config->ddc_data_gpio != -1) {
+                       ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
+                       if (ret) {
+                               dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
+                                       "HDMI_DDC_DATA", config->ddc_data_gpio, ret);
+                               goto error2;
+                       }
+                       gpio_set_value_cansleep(config->ddc_data_gpio, 1);
                }
-               gpio_set_value_cansleep(config->ddc_data_gpio, 1);
 
                ret = gpio_request(config->hpd_gpio, "HDMI_HPD");
                if (ret) {
@@ -94,8 +147,12 @@ static int gpio_config(struct hdmi *hdmi, bool on)
                }
                DBG("gpio on");
        } else {
-               gpio_free(config->ddc_clk_gpio);
-               gpio_free(config->ddc_data_gpio);
+               if (config->ddc_clk_gpio != -1)
+                       gpio_free(config->ddc_clk_gpio);
+
+               if (config->ddc_data_gpio != -1)
+                       gpio_free(config->ddc_data_gpio);
+
                gpio_free(config->hpd_gpio);
 
                if (config->mux_en_gpio != -1) {
@@ -126,9 +183,11 @@ error5:
 error4:
        gpio_free(config->hpd_gpio);
 error3:
-       gpio_free(config->ddc_data_gpio);
+       if (config->ddc_data_gpio != -1)
+               gpio_free(config->ddc_data_gpio);
 error2:
-       gpio_free(config->ddc_clk_gpio);
+       if (config->ddc_clk_gpio != -1)
+               gpio_free(config->ddc_clk_gpio);
 error1:
        return ret;
 }
@@ -138,9 +197,9 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
        struct hdmi *hdmi = hdmi_connector->hdmi;
        const struct hdmi_platform_config *config = hdmi->config;
        struct device *dev = &hdmi->pdev->dev;
-       struct hdmi_phy *phy = hdmi->phy;
        uint32_t hpd_ctrl;
        int i, ret;
+       unsigned long flags;
 
        for (i = 0; i < config->hpd_reg_cnt; i++) {
                ret = regulator_enable(hdmi->hpd_regs[i]);
@@ -181,7 +240,7 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
        }
 
        hdmi_set_mode(hdmi, false);
-       phy->funcs->reset(phy);
+       hdmi_phy_reset(hdmi);
        hdmi_set_mode(hdmi, true);
 
        hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b);
@@ -192,6 +251,7 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
                        HDMI_HPD_INT_CTRL_INT_EN);
 
        /* set timeout to 4.1ms (max) for hardware debounce */
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
        hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
        hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff);
 
@@ -200,6 +260,7 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
                        ~HDMI_HPD_CTRL_ENABLE & hpd_ctrl);
        hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
                        HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
 
        return 0;
 
@@ -250,7 +311,6 @@ hotplug_work(struct work_struct *work)
 void hdmi_connector_irq(struct drm_connector *connector)
 {
        struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
-       struct msm_drm_private *priv = connector->dev->dev_private;
        struct hdmi *hdmi = hdmi_connector->hdmi;
        uint32_t hpd_int_status, hpd_int_ctrl;
 
@@ -274,7 +334,7 @@ void hdmi_connector_irq(struct drm_connector *connector)
                        hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
                hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
 
-               queue_work(priv->wq, &hdmi_connector->hpd_work);
+               queue_work(hdmi->workq, &hdmi_connector->hpd_work);
        }
 }
 
@@ -350,6 +410,7 @@ static int hdmi_connector_get_modes(struct drm_connector *connector)
 
        hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
 
+       hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid);
        drm_mode_connector_update_edid_property(connector, edid);
 
        if (edid) {
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
new file mode 100644 (file)
index 0000000..1dc9c34
--- /dev/null
@@ -0,0 +1,1437 @@
+/* Copyright (c) 2010-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 "hdmi.h"
+#include <linux/qcom_scm.h>
+
+#define HDCP_REG_ENABLE 0x01
+#define HDCP_REG_DISABLE 0x00
+#define HDCP_PORT_ADDR 0x74
+
+#define HDCP_INT_STATUS_MASK ( \
+               HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_INT | \
+               HDMI_HDCP_INT_CTRL_AUTH_FAIL_INT | \
+               HDMI_HDCP_INT_CTRL_AUTH_XFER_REQ_INT | \
+               HDMI_HDCP_INT_CTRL_AUTH_XFER_DONE_INT)
+
+#define AUTH_WORK_RETRIES_TIME 100
+#define AUTH_RETRIES_TIME 30
+
+/* QFPROM Registers for HDMI/HDCP */
+#define QFPROM_RAW_FEAT_CONFIG_ROW0_LSB  0x000000F8
+#define QFPROM_RAW_FEAT_CONFIG_ROW0_MSB  0x000000FC
+#define HDCP_KSV_LSB                     0x000060D8
+#define HDCP_KSV_MSB                     0x000060DC
+
+enum DS_TYPE {  /* type of downstream device */
+       DS_UNKNOWN,
+       DS_RECEIVER,
+       DS_REPEATER,
+};
+
+enum hdmi_hdcp_state {
+       HDCP_STATE_NO_AKSV,
+       HDCP_STATE_INACTIVE,
+       HDCP_STATE_AUTHENTICATING,
+       HDCP_STATE_AUTHENTICATED,
+       HDCP_STATE_AUTH_FAILED
+};
+
+struct hdmi_hdcp_reg_data {
+       u32 reg_id;
+       u32 off;
+       char *name;
+       u32 reg_val;
+};
+
+struct hdmi_hdcp_ctrl {
+       struct hdmi *hdmi;
+       u32 auth_retries;
+       bool tz_hdcp;
+       enum hdmi_hdcp_state hdcp_state;
+       struct work_struct hdcp_auth_work;
+       struct work_struct hdcp_reauth_work;
+
+#define AUTH_ABORT_EV 1
+#define AUTH_RESULT_RDY_EV 2
+       unsigned long auth_event;
+       wait_queue_head_t auth_event_queue;
+
+       u32 ksv_fifo_w_index;
+       /*
+        * store aksv from qfprom
+        */
+       u32 aksv_lsb;
+       u32 aksv_msb;
+       bool aksv_valid;
+       u32 ds_type;
+       u32 bksv_lsb;
+       u32 bksv_msb;
+       u8 dev_count;
+       u8 depth;
+       u8 ksv_list[5 * 127];
+       bool max_cascade_exceeded;
+       bool max_dev_exceeded;
+};
+
+static int hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset,
+       u8 *data, u16 data_len)
+{
+       int rc;
+       int retry = 5;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = addr >> 1,
+                       .flags  = 0,
+                       .len    = 1,
+                       .buf    = &offset,
+               }, {
+                       .addr   = addr >> 1,
+                       .flags  = I2C_M_RD,
+                       .len    = data_len,
+                       .buf    = data,
+               }
+       };
+
+       DBG("Start DDC read");
+retry:
+       rc = i2c_transfer(hdmi->i2c, msgs, 2);
+
+       retry--;
+       if (rc == 2)
+               rc = 0;
+       else if (retry > 0)
+               goto retry;
+       else
+               rc = -EIO;
+
+       DBG("End DDC read %d", rc);
+
+       return rc;
+}
+
+#define HDCP_DDC_WRITE_MAX_BYTE_NUM 32
+
+static int hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset,
+       u8 *data, u16 data_len)
+{
+       int rc;
+       int retry = 10;
+       u8 buf[HDCP_DDC_WRITE_MAX_BYTE_NUM];
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = addr >> 1,
+                       .flags  = 0,
+                       .len    = 1,
+               }
+       };
+
+       DBG("Start DDC write");
+       if (data_len > (HDCP_DDC_WRITE_MAX_BYTE_NUM - 1)) {
+               pr_err("%s: write size too big\n", __func__);
+               return -ERANGE;
+       }
+
+       buf[0] = offset;
+       memcpy(&buf[1], data, data_len);
+       msgs[0].buf = buf;
+       msgs[0].len = data_len + 1;
+retry:
+       rc = i2c_transfer(hdmi->i2c, msgs, 1);
+
+       retry--;
+       if (rc == 1)
+               rc = 0;
+       else if (retry > 0)
+               goto retry;
+       else
+               rc = -EIO;
+
+       DBG("End DDC write %d", rc);
+
+       return rc;
+}
+
+static int hdmi_hdcp_scm_wr(struct hdmi_hdcp_ctrl *hdcp_ctrl, u32 *preg,
+       u32 *pdata, u32 count)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       struct qcom_scm_hdcp_req scm_buf[QCOM_SCM_HDCP_MAX_REQ_CNT];
+       u32 resp, phy_addr, idx = 0;
+       int i, ret = 0;
+
+       WARN_ON(!pdata || !preg || (count == 0));
+
+       if (hdcp_ctrl->tz_hdcp) {
+               phy_addr = (u32)hdmi->mmio_phy_addr;
+
+               while (count) {
+                       memset(scm_buf, 0, sizeof(scm_buf));
+                       for (i = 0; i < count && i < QCOM_SCM_HDCP_MAX_REQ_CNT;
+                               i++) {
+                               scm_buf[i].addr = phy_addr + preg[idx];
+                               scm_buf[i].val  = pdata[idx];
+                               idx++;
+                       }
+                       ret = qcom_scm_hdcp_req(scm_buf, i, &resp);
+
+                       if (ret || resp) {
+                               pr_err("%s: error: scm_call ret=%d resp=%u\n",
+                                       __func__, ret, resp);
+                               ret = -EINVAL;
+                               break;
+                       }
+
+                       count -= i;
+               }
+       } else {
+               for (i = 0; i < count; i++)
+                       hdmi_write(hdmi, preg[i], pdata[i]);
+       }
+
+       return ret;
+}
+
+void hdmi_hdcp_irq(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 reg_val, hdcp_int_status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_INT_CTRL);
+       hdcp_int_status = reg_val & HDCP_INT_STATUS_MASK;
+       if (!hdcp_int_status) {
+               spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+               return;
+       }
+       /* Clear Interrupts */
+       reg_val |= hdcp_int_status << 1;
+       /* Clear AUTH_FAIL_INFO as well */
+       if (hdcp_int_status & HDMI_HDCP_INT_CTRL_AUTH_FAIL_INT)
+               reg_val |= HDMI_HDCP_INT_CTRL_AUTH_FAIL_INFO_ACK;
+       hdmi_write(hdmi, REG_HDMI_HDCP_INT_CTRL, reg_val);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       DBG("hdcp irq %x", hdcp_int_status);
+
+       if (hdcp_int_status & HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_INT) {
+               pr_info("%s:AUTH_SUCCESS_INT received\n", __func__);
+               if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
+                       set_bit(AUTH_RESULT_RDY_EV, &hdcp_ctrl->auth_event);
+                       wake_up_all(&hdcp_ctrl->auth_event_queue);
+               }
+       }
+
+       if (hdcp_int_status & HDMI_HDCP_INT_CTRL_AUTH_FAIL_INT) {
+               reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
+               pr_info("%s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n",
+                       __func__, reg_val);
+               if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state)
+                       queue_work(hdmi->workq, &hdcp_ctrl->hdcp_reauth_work);
+               else if (HDCP_STATE_AUTHENTICATING ==
+                               hdcp_ctrl->hdcp_state) {
+                       set_bit(AUTH_RESULT_RDY_EV, &hdcp_ctrl->auth_event);
+                       wake_up_all(&hdcp_ctrl->auth_event_queue);
+               }
+       }
+}
+
+static int hdmi_hdcp_msleep(struct hdmi_hdcp_ctrl *hdcp_ctrl, u32 ms, u32 ev)
+{
+       int rc;
+
+       rc = wait_event_timeout(hdcp_ctrl->auth_event_queue,
+               !!test_bit(ev, &hdcp_ctrl->auth_event),
+               msecs_to_jiffies(ms));
+       if (rc) {
+               pr_info("%s: msleep is canceled by event %d\n",
+                               __func__, ev);
+               clear_bit(ev, &hdcp_ctrl->auth_event);
+               return -ECANCELED;
+       }
+
+       return 0;
+}
+
+static int hdmi_hdcp_read_validate_aksv(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+
+       /* Fetch aksv from QFPROM, this info should be public. */
+       hdcp_ctrl->aksv_lsb = hdmi_qfprom_read(hdmi, HDCP_KSV_LSB);
+       hdcp_ctrl->aksv_msb = hdmi_qfprom_read(hdmi, HDCP_KSV_MSB);
+
+       /* check there are 20 ones in AKSV */
+       if ((hweight32(hdcp_ctrl->aksv_lsb) + hweight32(hdcp_ctrl->aksv_msb))
+                       != 20) {
+               pr_err("%s: AKSV QFPROM doesn't have 20 1's, 20 0's\n",
+                       __func__);
+               pr_err("%s: QFPROM AKSV chk failed (AKSV=%02x%08x)\n",
+                       __func__, hdcp_ctrl->aksv_msb,
+                       hdcp_ctrl->aksv_lsb);
+               return -EINVAL;
+       }
+       DBG("AKSV=%02x%08x", hdcp_ctrl->aksv_msb, hdcp_ctrl->aksv_lsb);
+
+       return 0;
+}
+
+static int reset_hdcp_ddc_failures(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 reg_val, failure, nack0;
+       int rc = 0;
+
+       /* Check for any DDC transfer failures */
+       reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_STATUS);
+       failure = reg_val & HDMI_HDCP_DDC_STATUS_FAILED;
+       nack0 = reg_val & HDMI_HDCP_DDC_STATUS_NACK0;
+       DBG("HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d",
+               reg_val, failure, nack0);
+
+       if (failure) {
+               /*
+                * Indicates that the last HDCP HW DDC transfer failed.
+                * This occurs when a transfer is attempted with HDCP DDC
+                * disabled (HDCP_DDC_DISABLE=1) or the number of retries
+                * matches HDCP_DDC_RETRY_CNT.
+                * Failure occurred,  let's clear it.
+                */
+               DBG("DDC failure detected");
+
+               /* First, Disable DDC */
+               hdmi_write(hdmi, REG_HDMI_HDCP_DDC_CTRL_0,
+                       HDMI_HDCP_DDC_CTRL_0_DISABLE);
+
+               /* ACK the Failure to Clear it */
+               reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_CTRL_1);
+               reg_val |= HDMI_HDCP_DDC_CTRL_1_FAILED_ACK;
+               hdmi_write(hdmi, REG_HDMI_HDCP_DDC_CTRL_1, reg_val);
+
+               /* Check if the FAILURE got Cleared */
+               reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_STATUS);
+               if (reg_val & HDMI_HDCP_DDC_STATUS_FAILED)
+                       pr_info("%s: Unable to clear HDCP DDC Failure\n",
+                               __func__);
+
+               /* Re-Enable HDCP DDC */
+               hdmi_write(hdmi, REG_HDMI_HDCP_DDC_CTRL_0, 0);
+       }
+
+       if (nack0) {
+               DBG("Before: HDMI_DDC_SW_STATUS=0x%08x",
+                       hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS));
+               /* Reset HDMI DDC software status */
+               reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
+               reg_val |= HDMI_DDC_CTRL_SW_STATUS_RESET;
+               hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
+
+               rc = hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
+
+               reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
+               reg_val &= ~HDMI_DDC_CTRL_SW_STATUS_RESET;
+               hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
+
+               /* Reset HDMI DDC Controller */
+               reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
+               reg_val |= HDMI_DDC_CTRL_SOFT_RESET;
+               hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
+
+               /* If previous msleep is aborted, skip this msleep */
+               if (!rc)
+                       rc = hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
+
+               reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
+               reg_val &= ~HDMI_DDC_CTRL_SOFT_RESET;
+               hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
+               DBG("After: HDMI_DDC_SW_STATUS=0x%08x",
+                       hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS));
+       }
+
+       return rc;
+}
+
+static int hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int rc;
+       u32 hdcp_ddc_status, ddc_hw_status;
+       u32 xfer_done, xfer_req, hw_done;
+       bool hw_not_ready;
+       u32 timeout_count;
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+
+       if (hdmi_read(hdmi, REG_HDMI_DDC_HW_STATUS) == 0)
+               return 0;
+
+       /* Wait to be clean on DDC HW engine */
+       timeout_count = 100;
+       do {
+               hdcp_ddc_status = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_STATUS);
+               ddc_hw_status = hdmi_read(hdmi, REG_HDMI_DDC_HW_STATUS);
+
+               xfer_done = hdcp_ddc_status & HDMI_HDCP_DDC_STATUS_XFER_DONE;
+               xfer_req = hdcp_ddc_status & HDMI_HDCP_DDC_STATUS_XFER_REQ;
+               hw_done = ddc_hw_status & HDMI_DDC_HW_STATUS_DONE;
+               hw_not_ready = !xfer_done || xfer_req || !hw_done;
+
+               if (hw_not_ready)
+                       break;
+
+               timeout_count--;
+               if (!timeout_count) {
+                       pr_warn("%s: hw_ddc_clean failed\n", __func__);
+                       return -ETIMEDOUT;
+               }
+
+               rc = hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
+               if (rc)
+                       return rc;
+       } while (1);
+
+       return 0;
+}
+
+static void hdmi_hdcp_reauth_work(struct work_struct *work)
+{
+       struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(work,
+               struct hdmi_hdcp_ctrl, hdcp_reauth_work);
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       unsigned long flags;
+       u32 reg_val;
+
+       DBG("HDCP REAUTH WORK");
+       /*
+        * Disable HPD circuitry.
+        * This is needed to reset the HDCP cipher engine so that when we
+        * attempt a re-authentication, HW would clear the AN0_READY and
+        * AN1_READY bits in HDMI_HDCP_LINK0_STATUS register
+        */
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
+       reg_val &= ~HDMI_HPD_CTRL_ENABLE;
+       hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
+
+       /* Disable HDCP interrupts */
+       hdmi_write(hdmi, REG_HDMI_HDCP_INT_CTRL, 0);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       hdmi_write(hdmi, REG_HDMI_HDCP_RESET,
+               HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE);
+
+       /* Wait to be clean on DDC HW engine */
+       if (hdmi_hdcp_hw_ddc_clean(hdcp_ctrl)) {
+               pr_info("%s: reauth work aborted\n", __func__);
+               return;
+       }
+
+       /* Disable encryption and disable the HDCP block */
+       hdmi_write(hdmi, REG_HDMI_HDCP_CTRL, 0);
+
+       /* Enable HPD circuitry */
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
+       reg_val |= HDMI_HPD_CTRL_ENABLE;
+       hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       /*
+        * Only retry defined times then abort current authenticating process
+        */
+       if (++hdcp_ctrl->auth_retries == AUTH_RETRIES_TIME) {
+               hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
+               hdcp_ctrl->auth_retries = 0;
+               pr_info("%s: abort reauthentication!\n", __func__);
+
+               return;
+       }
+
+       DBG("Queue AUTH WORK");
+       hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
+       queue_work(hdmi->workq, &hdcp_ctrl->hdcp_auth_work);
+}
+
+static int hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 link0_status;
+       u32 reg_val;
+       unsigned long flags;
+       int rc;
+
+       if (!hdcp_ctrl->aksv_valid) {
+               rc = hdmi_hdcp_read_validate_aksv(hdcp_ctrl);
+               if (rc) {
+                       pr_err("%s: ASKV validation failed\n", __func__);
+                       hdcp_ctrl->hdcp_state = HDCP_STATE_NO_AKSV;
+                       return -ENOTSUPP;
+               }
+               hdcp_ctrl->aksv_valid = true;
+       }
+
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       /* disable HDMI Encrypt */
+       reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
+       reg_val &= ~HDMI_CTRL_ENCRYPTED;
+       hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
+
+       /* Enabling Software DDC */
+       reg_val = hdmi_read(hdmi, REG_HDMI_DDC_ARBITRATION);
+       reg_val &= ~HDMI_DDC_ARBITRATION_HW_ARBITRATION;
+       hdmi_write(hdmi, REG_HDMI_DDC_ARBITRATION, reg_val);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       /*
+        * Write AKSV read from QFPROM to the HDCP registers.
+        * This step is needed for HDCP authentication and must be
+        * written before enabling HDCP.
+        */
+       hdmi_write(hdmi, REG_HDMI_HDCP_SW_LOWER_AKSV, hdcp_ctrl->aksv_lsb);
+       hdmi_write(hdmi, REG_HDMI_HDCP_SW_UPPER_AKSV, hdcp_ctrl->aksv_msb);
+
+       /*
+        * HDCP setup prior to enabling HDCP_CTRL.
+        * Setup seed values for random number An.
+        */
+       hdmi_write(hdmi, REG_HDMI_HDCP_ENTROPY_CTRL0, 0xB1FFB0FF);
+       hdmi_write(hdmi, REG_HDMI_HDCP_ENTROPY_CTRL1, 0xF00DFACE);
+
+       /* Disable the RngCipher state */
+       reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DEBUG_CTRL);
+       reg_val &= ~HDMI_HDCP_DEBUG_CTRL_RNG_CIPHER;
+       hdmi_write(hdmi, REG_HDMI_HDCP_DEBUG_CTRL, reg_val);
+       DBG("HDCP_DEBUG_CTRL=0x%08x",
+               hdmi_read(hdmi, REG_HDMI_HDCP_DEBUG_CTRL));
+
+       /*
+        * Ensure that all register writes are completed before
+        * enabling HDCP cipher
+        */
+       wmb();
+
+       /*
+        * Enable HDCP
+        * This needs to be done as early as possible in order for the
+        * hardware to make An available to read
+        */
+       hdmi_write(hdmi, REG_HDMI_HDCP_CTRL, HDMI_HDCP_CTRL_ENABLE);
+
+       /*
+        * If we had stale values for the An ready bit, it should most
+        * likely be cleared now after enabling HDCP cipher
+        */
+       link0_status = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
+       DBG("After enabling HDCP Link0_Status=0x%08x", link0_status);
+       if (!(link0_status &
+               (HDMI_HDCP_LINK0_STATUS_AN_0_READY |
+               HDMI_HDCP_LINK0_STATUS_AN_1_READY)))
+               DBG("An not ready after enabling HDCP");
+
+       /* Clear any DDC failures from previous tries before enable HDCP*/
+       rc = reset_hdcp_ddc_failures(hdcp_ctrl);
+
+       return rc;
+}
+
+static void hdmi_hdcp_auth_fail(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 reg_val;
+       unsigned long flags;
+
+       DBG("hdcp auth failed, queue reauth work");
+       /* clear HDMI Encrypt */
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
+       reg_val &= ~HDMI_CTRL_ENCRYPTED;
+       hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAILED;
+       queue_work(hdmi->workq, &hdcp_ctrl->hdcp_reauth_work);
+}
+
+static void hdmi_hdcp_auth_done(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 reg_val;
+       unsigned long flags;
+
+       /*
+        * Disable software DDC before going into part3 to make sure
+        * there is no Arbitration between software and hardware for DDC
+        */
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       reg_val = hdmi_read(hdmi, REG_HDMI_DDC_ARBITRATION);
+       reg_val |= HDMI_DDC_ARBITRATION_HW_ARBITRATION;
+       hdmi_write(hdmi, REG_HDMI_DDC_ARBITRATION, reg_val);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       /* enable HDMI Encrypt */
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
+       reg_val |= HDMI_CTRL_ENCRYPTED;
+       hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATED;
+       hdcp_ctrl->auth_retries = 0;
+}
+
+/*
+ * hdcp authenticating part 1
+ * Wait Key/An ready
+ * Read BCAPS from sink
+ * Write BCAPS and AKSV into HDCP engine
+ * Write An and AKSV to sink
+ * Read BKSV from sink and write into HDCP engine
+ */
+static int hdmi_hdcp_wait_key_an_ready(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int rc;
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 link0_status, keys_state;
+       u32 timeout_count;
+       bool an_ready;
+
+       /* Wait for HDCP keys to be checked and validated */
+       timeout_count = 100;
+       do {
+               link0_status = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
+               keys_state = (link0_status >> 28) & 0x7;
+               if (keys_state == HDCP_KEYS_STATE_VALID)
+                       break;
+
+               DBG("Keys not ready(%d). s=%d, l0=%0x08x",
+                       timeout_count, keys_state, link0_status);
+
+               timeout_count--;
+               if (!timeout_count) {
+                       pr_err("%s: Wait key state timedout", __func__);
+                       return -ETIMEDOUT;
+               }
+
+               rc = hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
+               if (rc)
+                       return rc;
+       } while (1);
+
+       timeout_count = 100;
+       do {
+               link0_status = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
+               an_ready = (link0_status & HDMI_HDCP_LINK0_STATUS_AN_0_READY)
+                       && (link0_status & HDMI_HDCP_LINK0_STATUS_AN_1_READY);
+               if (an_ready)
+                       break;
+
+               DBG("An not ready(%d). l0_status=0x%08x",
+                       timeout_count, link0_status);
+
+               timeout_count--;
+               if (!timeout_count) {
+                       pr_err("%s: Wait An timedout", __func__);
+                       return -ETIMEDOUT;
+               }
+
+               rc = hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
+               if (rc)
+                       return rc;
+       } while (1);
+
+       return 0;
+}
+
+static int hdmi_hdcp_send_aksv_an(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int rc = 0;
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 link0_aksv_0, link0_aksv_1;
+       u32 link0_an[2];
+       u8 aksv[5];
+
+       /* Read An0 and An1 */
+       link0_an[0] = hdmi_read(hdmi, REG_HDMI_HDCP_RCVPORT_DATA5);
+       link0_an[1] = hdmi_read(hdmi, REG_HDMI_HDCP_RCVPORT_DATA6);
+
+       /* Read AKSV */
+       link0_aksv_0 = hdmi_read(hdmi, REG_HDMI_HDCP_RCVPORT_DATA3);
+       link0_aksv_1 = hdmi_read(hdmi, REG_HDMI_HDCP_RCVPORT_DATA4);
+
+       DBG("Link ASKV=%08x%08x", link0_aksv_0, link0_aksv_1);
+       /* Copy An and AKSV to byte arrays for transmission */
+       aksv[0] =  link0_aksv_0        & 0xFF;
+       aksv[1] = (link0_aksv_0 >> 8)  & 0xFF;
+       aksv[2] = (link0_aksv_0 >> 16) & 0xFF;
+       aksv[3] = (link0_aksv_0 >> 24) & 0xFF;
+       aksv[4] =  link0_aksv_1        & 0xFF;
+
+       /* Write An to offset 0x18 */
+       rc = hdmi_ddc_write(hdmi, HDCP_PORT_ADDR, 0x18, (u8 *)link0_an,
+               (u16)sizeof(link0_an));
+       if (rc) {
+               pr_err("%s:An write failed\n", __func__);
+               return rc;
+       }
+       DBG("Link0-An=%08x%08x", link0_an[0], link0_an[1]);
+
+       /* Write AKSV to offset 0x10 */
+       rc = hdmi_ddc_write(hdmi, HDCP_PORT_ADDR, 0x10, aksv, 5);
+       if (rc) {
+               pr_err("%s:AKSV write failed\n", __func__);
+               return rc;
+       }
+       DBG("Link0-AKSV=%02x%08x", link0_aksv_1 & 0xFF, link0_aksv_0);
+
+       return 0;
+}
+
+static int hdmi_hdcp_recv_bksv(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int rc = 0;
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u8 bksv[5];
+       u32 reg[2], data[2];
+
+       /* Read BKSV at offset 0x00 */
+       rc = hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x00, bksv, 5);
+       if (rc) {
+               pr_err("%s:BKSV read failed\n", __func__);
+               return rc;
+       }
+
+       hdcp_ctrl->bksv_lsb = bksv[0] | (bksv[1] << 8) |
+               (bksv[2] << 16) | (bksv[3] << 24);
+       hdcp_ctrl->bksv_msb = bksv[4];
+       DBG(":BKSV=%02x%08x", hdcp_ctrl->bksv_msb, hdcp_ctrl->bksv_lsb);
+
+       /* check there are 20 ones in BKSV */
+       if ((hweight32(hdcp_ctrl->bksv_lsb) + hweight32(hdcp_ctrl->bksv_msb))
+                       != 20) {
+               pr_err(": BKSV doesn't have 20 1's and 20 0's\n");
+               pr_err(": BKSV chk fail. BKSV=%02x%02x%02x%02x%02x\n",
+                       bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]);
+               return -EINVAL;
+       }
+
+       /* Write BKSV read from sink to HDCP registers */
+       reg[0] = REG_HDMI_HDCP_RCVPORT_DATA0;
+       data[0] = hdcp_ctrl->bksv_lsb;
+       reg[1] = REG_HDMI_HDCP_RCVPORT_DATA1;
+       data[1] = hdcp_ctrl->bksv_msb;
+       rc = hdmi_hdcp_scm_wr(hdcp_ctrl, reg, data, 2);
+
+       return rc;
+}
+
+static int hdmi_hdcp_recv_bcaps(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int rc = 0;
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 reg, data;
+       u8 bcaps;
+
+       rc = hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x40, &bcaps, 1);
+       if (rc) {
+               pr_err("%s:BCAPS read failed\n", __func__);
+               return rc;
+       }
+       DBG("BCAPS=%02x", bcaps);
+
+       /* receiver (0), repeater (1) */
+       hdcp_ctrl->ds_type = (bcaps & BIT(6)) ? DS_REPEATER : DS_RECEIVER;
+
+       /* Write BCAPS to the hardware */
+       reg = REG_HDMI_HDCP_RCVPORT_DATA12;
+       data = (u32)bcaps;
+       rc = hdmi_hdcp_scm_wr(hdcp_ctrl, &reg, &data, 1);
+
+       return rc;
+}
+
+static int hdmi_hdcp_auth_part1_key_exchange(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       unsigned long flags;
+       int rc;
+
+       /* Wait for AKSV key and An ready */
+       rc = hdmi_hdcp_wait_key_an_ready(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: wait key and an ready failed\n", __func__);
+               return rc;
+       };
+
+       /* Read BCAPS and send to HDCP engine */
+       rc = hdmi_hdcp_recv_bcaps(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: read bcaps error, abort\n", __func__);
+               return rc;
+       }
+
+       /*
+        * 1.1_Features turned off by default.
+        * No need to write AInfo since 1.1_Features is disabled.
+        */
+       hdmi_write(hdmi, REG_HDMI_HDCP_RCVPORT_DATA4, 0);
+
+       /* Send AKSV and An to sink */
+       rc = hdmi_hdcp_send_aksv_an(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s:An/Aksv write failed\n", __func__);
+               return rc;
+       }
+
+       /* Read BKSV and send to HDCP engine*/
+       rc = hdmi_hdcp_recv_bksv(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s:BKSV Process failed\n", __func__);
+               return rc;
+       }
+
+       /* Enable HDCP interrupts and ack/clear any stale interrupts */
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       hdmi_write(hdmi, REG_HDMI_HDCP_INT_CTRL,
+               HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_ACK |
+               HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_MASK |
+               HDMI_HDCP_INT_CTRL_AUTH_FAIL_ACK |
+               HDMI_HDCP_INT_CTRL_AUTH_FAIL_MASK |
+               HDMI_HDCP_INT_CTRL_AUTH_FAIL_INFO_ACK);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       return 0;
+}
+
+/* read R0' from sink and pass it to HDCP engine */
+static int hdmi_hdcp_auth_part1_recv_r0(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       int rc = 0;
+       u8 buf[2];
+
+       /*
+        * HDCP Compliance Test case 1A-01:
+        * Wait here at least 100ms before reading R0'
+        */
+       rc = hdmi_hdcp_msleep(hdcp_ctrl, 125, AUTH_ABORT_EV);
+       if (rc)
+               return rc;
+
+       /* Read R0' at offset 0x08 */
+       rc = hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x08, buf, 2);
+       if (rc) {
+               pr_err("%s:R0' read failed\n", __func__);
+               return rc;
+       }
+       DBG("R0'=%02x%02x", buf[1], buf[0]);
+
+       /* Write R0' to HDCP registers and check to see if it is a match */
+       hdmi_write(hdmi, REG_HDMI_HDCP_RCVPORT_DATA2_0,
+               (((u32)buf[1]) << 8) | buf[0]);
+
+       return 0;
+}
+
+/* Wait for authenticating result: R0/R0' are matched or not */
+static int hdmi_hdcp_auth_part1_verify_r0(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 link0_status;
+       int rc;
+
+       /* wait for hdcp irq, 10 sec should be long enough */
+       rc = hdmi_hdcp_msleep(hdcp_ctrl, 10000, AUTH_RESULT_RDY_EV);
+       if (!rc) {
+               pr_err("%s: Wait Auth IRQ timeout\n", __func__);
+               return -ETIMEDOUT;
+       }
+
+       link0_status = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
+       if (!(link0_status & HDMI_HDCP_LINK0_STATUS_RI_MATCHES)) {
+               pr_err("%s: Authentication Part I failed\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Enable HDCP Encryption */
+       hdmi_write(hdmi, REG_HDMI_HDCP_CTRL,
+               HDMI_HDCP_CTRL_ENABLE |
+               HDMI_HDCP_CTRL_ENCRYPTION_ENABLE);
+
+       return 0;
+}
+
+static int hdmi_hdcp_recv_check_bstatus(struct hdmi_hdcp_ctrl *hdcp_ctrl,
+       u16 *pbstatus)
+{
+       int rc;
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       bool max_devs_exceeded = false, max_cascade_exceeded = false;
+       u32 repeater_cascade_depth = 0, down_stream_devices = 0;
+       u16 bstatus;
+       u8 buf[2];
+
+       /* Read BSTATUS at offset 0x41 */
+       rc = hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x41, buf, 2);
+       if (rc) {
+               pr_err("%s: BSTATUS read failed\n", __func__);
+               goto error;
+       }
+       *pbstatus = bstatus = (buf[1] << 8) | buf[0];
+
+
+       down_stream_devices = bstatus & 0x7F;
+       repeater_cascade_depth = (bstatus >> 8) & 0x7;
+       max_devs_exceeded = (bstatus & BIT(7)) ? true : false;
+       max_cascade_exceeded = (bstatus & BIT(11)) ? true : false;
+
+       if (down_stream_devices == 0) {
+               /*
+                * If no downstream devices are attached to the repeater
+                * then part II fails.
+                * todo: The other approach would be to continue PART II.
+                */
+               pr_err("%s: No downstream devices\n", __func__);
+               rc = -EINVAL;
+               goto error;
+       }
+
+       /*
+        * HDCP Compliance 1B-05:
+        * Check if no. of devices connected to repeater
+        * exceed max_devices_connected from bit 7 of Bstatus.
+        */
+       if (max_devs_exceeded) {
+               pr_err("%s: no. of devs connected exceeds max allowed",
+                       __func__);
+               rc = -EINVAL;
+               goto error;
+       }
+
+       /*
+        * HDCP Compliance 1B-06:
+        * Check if no. of cascade connected to repeater
+        * exceed max_cascade_connected from bit 11 of Bstatus.
+        */
+       if (max_cascade_exceeded) {
+               pr_err("%s: no. of cascade conn exceeds max allowed",
+                       __func__);
+               rc = -EINVAL;
+               goto error;
+       }
+
+error:
+       hdcp_ctrl->dev_count = down_stream_devices;
+       hdcp_ctrl->max_cascade_exceeded = max_cascade_exceeded;
+       hdcp_ctrl->max_dev_exceeded = max_devs_exceeded;
+       hdcp_ctrl->depth = repeater_cascade_depth;
+       return rc;
+}
+
+static int hdmi_hdcp_auth_part2_wait_ksv_fifo_ready(
+       struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int rc;
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 reg, data;
+       u32 timeout_count;
+       u16 bstatus;
+       u8 bcaps;
+
+       /*
+        * Wait until READY bit is set in BCAPS, as per HDCP specifications
+        * maximum permitted time to check for READY bit is five seconds.
+        */
+       timeout_count = 100;
+       do {
+               /* Read BCAPS at offset 0x40 */
+               rc = hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x40, &bcaps, 1);
+               if (rc) {
+                       pr_err("%s: BCAPS read failed\n", __func__);
+                       return rc;
+               }
+
+               if (bcaps & BIT(5))
+                       break;
+
+               timeout_count--;
+               if (!timeout_count) {
+                       pr_err("%s: Wait KSV fifo ready timedout", __func__);
+                       return -ETIMEDOUT;
+               }
+
+               rc = hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
+               if (rc)
+                       return rc;
+       } while (1);
+
+       rc = hdmi_hdcp_recv_check_bstatus(hdcp_ctrl, &bstatus);
+       if (rc) {
+               pr_err("%s: bstatus error\n", __func__);
+               return rc;
+       }
+
+       /* Write BSTATUS and BCAPS to HDCP registers */
+       reg = REG_HDMI_HDCP_RCVPORT_DATA12;
+       data = bcaps | (bstatus << 8);
+       rc = hdmi_hdcp_scm_wr(hdcp_ctrl, &reg, &data, 1);
+       if (rc) {
+               pr_err("%s: BSTATUS write failed\n", __func__);
+               return rc;
+       }
+
+       return 0;
+}
+
+/*
+ * hdcp authenticating part 2: 2nd
+ * read ksv fifo from sink
+ * transfer V' from sink to HDCP engine
+ * reset SHA engine
+ */
+static int hdmi_hdcp_transfer_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       int rc = 0;
+       struct hdmi_hdcp_reg_data reg_data[]  = {
+               {REG_HDMI_HDCP_RCVPORT_DATA7,  0x20, "V' H0"},
+               {REG_HDMI_HDCP_RCVPORT_DATA8,  0x24, "V' H1"},
+               {REG_HDMI_HDCP_RCVPORT_DATA9,  0x28, "V' H2"},
+               {REG_HDMI_HDCP_RCVPORT_DATA10, 0x2C, "V' H3"},
+               {REG_HDMI_HDCP_RCVPORT_DATA11, 0x30, "V' H4"},
+       };
+       struct hdmi_hdcp_reg_data *rd;
+       u32 size = ARRAY_SIZE(reg_data);
+       u32 reg[ARRAY_SIZE(reg_data)];
+       u32 data[ARRAY_SIZE(reg_data)];
+       int i;
+
+       for (i = 0; i < size; i++) {
+               rd = &reg_data[i];
+               rc = hdmi_ddc_read(hdmi, HDCP_PORT_ADDR,
+                       rd->off, (u8 *)&data[i], (u16)sizeof(data[i]));
+               if (rc) {
+                       pr_err("%s: Read %s failed\n", __func__, rd->name);
+                       goto error;
+               }
+
+               DBG("%s =%x", rd->name, data[i]);
+               reg[i] = reg_data[i].reg_id;
+       }
+
+       rc = hdmi_hdcp_scm_wr(hdcp_ctrl, reg, data, size);
+
+error:
+       return rc;
+}
+
+static int hdmi_hdcp_recv_ksv_fifo(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int rc;
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 ksv_bytes;
+
+       ksv_bytes = 5 * hdcp_ctrl->dev_count;
+
+       rc = hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x43,
+               hdcp_ctrl->ksv_list, ksv_bytes);
+       if (rc)
+               pr_err("%s: KSV FIFO read failed\n", __func__);
+
+       return rc;
+}
+
+static int hdmi_hdcp_reset_sha_engine(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       u32 reg[2], data[2];
+       u32 rc  = 0;
+
+       reg[0] = REG_HDMI_HDCP_SHA_CTRL;
+       data[0] = HDCP_REG_ENABLE;
+       reg[1] = REG_HDMI_HDCP_SHA_CTRL;
+       data[1] = HDCP_REG_DISABLE;
+
+       rc = hdmi_hdcp_scm_wr(hdcp_ctrl, reg, data, 2);
+
+       return rc;
+}
+
+static int hdmi_hdcp_auth_part2_recv_ksv_fifo(
+       struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int rc;
+       u32 timeout_count;
+
+       /*
+        * Read KSV FIFO over DDC
+        * Key Selection vector FIFO Used to pull downstream KSVs
+        * from HDCP Repeaters.
+        * All bytes (DEVICE_COUNT * 5) must be read in a single,
+        * auto incrementing access.
+        * All bytes read as 0x00 for HDCP Receivers that are not
+        * HDCP Repeaters (REPEATER == 0).
+        */
+       timeout_count = 100;
+       do {
+               rc = hdmi_hdcp_recv_ksv_fifo(hdcp_ctrl);
+               if (!rc)
+                       break;
+
+               timeout_count--;
+               if (!timeout_count) {
+                       pr_err("%s: Recv ksv fifo timedout", __func__);
+                       return -ETIMEDOUT;
+               }
+
+               rc = hdmi_hdcp_msleep(hdcp_ctrl, 25, AUTH_ABORT_EV);
+               if (rc)
+                       return rc;
+       } while (1);
+
+       rc = hdmi_hdcp_transfer_v_h(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: transfer V failed\n", __func__);
+               return rc;
+       }
+
+       /* reset SHA engine before write ksv fifo */
+       rc = hdmi_hdcp_reset_sha_engine(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: fail to reset sha engine\n", __func__);
+               return rc;
+       }
+
+       return 0;
+}
+
+/*
+ * Write KSV FIFO to HDCP_SHA_DATA.
+ * This is done 1 byte at time starting with the LSB.
+ * Once 64 bytes have been written, we need to poll for
+ * HDCP_SHA_BLOCK_DONE before writing any further
+ * If the last byte is written, we need to poll for
+ * HDCP_SHA_COMP_DONE to wait until HW finish
+ */
+static int hdmi_hdcp_write_ksv_fifo(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int i;
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 ksv_bytes, last_byte = 0;
+       u8 *ksv_fifo = NULL;
+       u32 reg_val, data, reg;
+       u32 rc  = 0;
+
+       ksv_bytes  = 5 * hdcp_ctrl->dev_count;
+
+       /* Check if need to wait for HW completion */
+       if (hdcp_ctrl->ksv_fifo_w_index) {
+               reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_SHA_STATUS);
+               DBG("HDCP_SHA_STATUS=%08x", reg_val);
+               if (hdcp_ctrl->ksv_fifo_w_index == ksv_bytes) {
+                       /* check COMP_DONE if last write */
+                       if (reg_val & HDMI_HDCP_SHA_STATUS_COMP_DONE) {
+                               DBG("COMP_DONE");
+                               return 0;
+                       } else {
+                               return -EAGAIN;
+                       }
+               } else {
+                       /* check BLOCK_DONE if not last write */
+                       if (!(reg_val & HDMI_HDCP_SHA_STATUS_BLOCK_DONE))
+                               return -EAGAIN;
+
+                       DBG("BLOCK_DONE");
+               }
+       }
+
+       ksv_bytes  -= hdcp_ctrl->ksv_fifo_w_index;
+       if (ksv_bytes <= 64)
+               last_byte = 1;
+       else
+               ksv_bytes = 64;
+
+       ksv_fifo = hdcp_ctrl->ksv_list;
+       ksv_fifo += hdcp_ctrl->ksv_fifo_w_index;
+
+       for (i = 0; i < ksv_bytes; i++) {
+               /* Write KSV byte and set DONE bit[0] for last byte*/
+               reg_val = ksv_fifo[i] << 16;
+               if ((i == (ksv_bytes - 1)) && last_byte)
+                       reg_val |= HDMI_HDCP_SHA_DATA_DONE;
+
+               reg = REG_HDMI_HDCP_SHA_DATA;
+               data = reg_val;
+               rc = hdmi_hdcp_scm_wr(hdcp_ctrl, &reg, &data, 1);
+
+               if (rc)
+                       return rc;
+       }
+
+       hdcp_ctrl->ksv_fifo_w_index += ksv_bytes;
+
+       /*
+        *return -EAGAIN to notify caller to wait for COMP_DONE or BLOCK_DONE
+        */
+       return -EAGAIN;
+}
+
+/* write ksv fifo into HDCP engine */
+static int hdmi_hdcp_auth_part2_write_ksv_fifo(
+       struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int rc;
+       u32 timeout_count;
+
+       hdcp_ctrl->ksv_fifo_w_index = 0;
+       timeout_count = 100;
+       do {
+               rc = hdmi_hdcp_write_ksv_fifo(hdcp_ctrl);
+               if (!rc)
+                       break;
+
+               if (rc != -EAGAIN)
+                       return rc;
+
+               timeout_count--;
+               if (!timeout_count) {
+                       pr_err("%s: Write KSV fifo timedout", __func__);
+                       return -ETIMEDOUT;
+               }
+
+               rc = hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
+               if (rc)
+                       return rc;
+       } while (1);
+
+       return 0;
+}
+
+static int hdmi_hdcp_auth_part2_check_v_match(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       int rc = 0;
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 link0_status;
+       u32 timeout_count = 100;
+
+       do {
+               link0_status = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
+               if (link0_status & HDMI_HDCP_LINK0_STATUS_V_MATCHES)
+                       break;
+
+               timeout_count--;
+               if (!timeout_count) {
+                               pr_err("%s: HDCP V Match timedout", __func__);
+                               return -ETIMEDOUT;
+               }
+
+               rc = hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
+               if (rc)
+                       return rc;
+       } while (1);
+
+       return 0;
+}
+
+static void hdmi_hdcp_auth_work(struct work_struct *work)
+{
+       struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(work,
+               struct hdmi_hdcp_ctrl, hdcp_auth_work);
+       int rc;
+
+       rc = hdmi_hdcp_auth_prepare(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: auth prepare failed %d\n", __func__, rc);
+               goto end;
+       }
+
+       /* HDCP PartI */
+       rc = hdmi_hdcp_auth_part1_key_exchange(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: key exchange failed %d\n", __func__, rc);
+               goto end;
+       }
+
+       rc = hdmi_hdcp_auth_part1_recv_r0(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: receive r0 failed %d\n", __func__, rc);
+               goto end;
+       }
+
+       rc = hdmi_hdcp_auth_part1_verify_r0(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: verify r0 failed %d\n", __func__, rc);
+               goto end;
+       }
+       pr_info("%s: Authentication Part I successful\n", __func__);
+       if (hdcp_ctrl->ds_type == DS_RECEIVER)
+               goto end;
+
+       /* HDCP PartII */
+       rc = hdmi_hdcp_auth_part2_wait_ksv_fifo_ready(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: wait ksv fifo ready failed %d\n", __func__, rc);
+               goto end;
+       }
+
+       rc = hdmi_hdcp_auth_part2_recv_ksv_fifo(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: recv ksv fifo failed %d\n", __func__, rc);
+               goto end;
+       }
+
+       rc = hdmi_hdcp_auth_part2_write_ksv_fifo(hdcp_ctrl);
+       if (rc) {
+               pr_err("%s: write ksv fifo failed %d\n", __func__, rc);
+               goto end;
+       }
+
+       rc = hdmi_hdcp_auth_part2_check_v_match(hdcp_ctrl);
+       if (rc)
+               pr_err("%s: check v match failed %d\n", __func__, rc);
+
+end:
+       if (rc == -ECANCELED) {
+               pr_info("%s: hdcp authentication canceled\n", __func__);
+       } else if (rc == -ENOTSUPP) {
+               pr_info("%s: hdcp is not supported\n", __func__);
+       } else if (rc) {
+               pr_err("%s: hdcp authentication failed\n", __func__);
+               hdmi_hdcp_auth_fail(hdcp_ctrl);
+       } else {
+               hdmi_hdcp_auth_done(hdcp_ctrl);
+       }
+}
+
+void hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       u32 reg_val;
+       unsigned long flags;
+
+       if ((HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) ||
+               (HDCP_STATE_NO_AKSV == hdcp_ctrl->hdcp_state)) {
+               DBG("still active or activating or no askv. returning");
+               return;
+       }
+
+       /* clear HDMI Encrypt */
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
+       reg_val &= ~HDMI_CTRL_ENCRYPTED;
+       hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       hdcp_ctrl->auth_event = 0;
+       hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
+       hdcp_ctrl->auth_retries = 0;
+       queue_work(hdmi->workq, &hdcp_ctrl->hdcp_auth_work);
+}
+
+void hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+       struct hdmi *hdmi = hdcp_ctrl->hdmi;
+       unsigned long flags;
+       u32 reg_val;
+
+       if ((HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) ||
+               (HDCP_STATE_NO_AKSV == hdcp_ctrl->hdcp_state)) {
+               DBG("hdcp inactive or no aksv. returning");
+               return;
+       }
+
+       /*
+        * Disable HPD circuitry.
+        * This is needed to reset the HDCP cipher engine so that when we
+        * attempt a re-authentication, HW would clear the AN0_READY and
+        * AN1_READY bits in HDMI_HDCP_LINK0_STATUS register
+        */
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
+       reg_val &= ~HDMI_HPD_CTRL_ENABLE;
+       hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
+
+       /*
+        * Disable HDCP interrupts.
+        * Also, need to set the state to inactive here so that any ongoing
+        * reauth works will know that the HDCP session has been turned off.
+        */
+       hdmi_write(hdmi, REG_HDMI_HDCP_INT_CTRL, 0);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       /*
+        * Cancel any pending auth/reauth attempts.
+        * If one is ongoing, this will wait for it to finish.
+        * No more reauthentication attempts will be scheduled since we
+        * set the current state to inactive.
+        */
+       set_bit(AUTH_ABORT_EV, &hdcp_ctrl->auth_event);
+       wake_up_all(&hdcp_ctrl->auth_event_queue);
+       cancel_work_sync(&hdcp_ctrl->hdcp_auth_work);
+       cancel_work_sync(&hdcp_ctrl->hdcp_reauth_work);
+
+       hdmi_write(hdmi, REG_HDMI_HDCP_RESET,
+               HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE);
+
+       /* Disable encryption and disable the HDCP block */
+       hdmi_write(hdmi, REG_HDMI_HDCP_CTRL, 0);
+
+       spin_lock_irqsave(&hdmi->reg_lock, flags);
+       reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
+       reg_val &= ~HDMI_CTRL_ENCRYPTED;
+       hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
+
+       /* Enable HPD circuitry */
+       reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
+       reg_val |= HDMI_HPD_CTRL_ENABLE;
+       hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
+       spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+
+       hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
+
+       DBG("HDCP: Off");
+}
+
+struct hdmi_hdcp_ctrl *hdmi_hdcp_init(struct hdmi *hdmi)
+{
+       struct hdmi_hdcp_ctrl *hdcp_ctrl = NULL;
+
+       if (!hdmi->qfprom_mmio) {
+               pr_err("%s: HDCP is not supported without qfprom\n",
+                       __func__);
+               return ERR_PTR(-EINVAL);
+       }
+
+       hdcp_ctrl = kzalloc(sizeof(*hdcp_ctrl), GFP_KERNEL);
+       if (!hdcp_ctrl)
+               return ERR_PTR(-ENOMEM);
+
+       INIT_WORK(&hdcp_ctrl->hdcp_auth_work, hdmi_hdcp_auth_work);
+       INIT_WORK(&hdcp_ctrl->hdcp_reauth_work, hdmi_hdcp_reauth_work);
+       init_waitqueue_head(&hdcp_ctrl->auth_event_queue);
+       hdcp_ctrl->hdmi = hdmi;
+       hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
+       hdcp_ctrl->aksv_valid = false;
+
+       if (qcom_scm_hdcp_available())
+               hdcp_ctrl->tz_hdcp = true;
+       else
+               hdcp_ctrl->tz_hdcp = false;
+
+       return hdcp_ctrl;
+}
+
+void hdmi_hdcp_destroy(struct hdmi *hdmi)
+{
+       if (hdmi && hdmi->hdcp_ctrl) {
+               kfree(hdmi->hdcp_ctrl);
+               hdmi->hdcp_ctrl = NULL;
+       }
+}
index 6997ec636c6d473413227f0701e3f1c72b94988c..3a01cb5051e2db05b7757ee95d3d994aa393b625 100644 (file)
@@ -426,57 +426,6 @@ static void hdmi_phy_8960_destroy(struct hdmi_phy *phy)
        kfree(phy_8960);
 }
 
-static void hdmi_phy_8960_reset(struct hdmi_phy *phy)
-{
-       struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
-       struct hdmi *hdmi = phy_8960->hdmi;
-       unsigned int val;
-
-       val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
-
-       if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
-               /* pull low */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val & ~HDMI_PHY_CTRL_SW_RESET);
-       } else {
-               /* pull high */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val | HDMI_PHY_CTRL_SW_RESET);
-       }
-
-       if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
-               /* pull low */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
-       } else {
-               /* pull high */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val | HDMI_PHY_CTRL_SW_RESET_PLL);
-       }
-
-       msleep(100);
-
-       if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
-               /* pull high */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val | HDMI_PHY_CTRL_SW_RESET);
-       } else {
-               /* pull low */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val & ~HDMI_PHY_CTRL_SW_RESET);
-       }
-
-       if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
-               /* pull high */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val | HDMI_PHY_CTRL_SW_RESET_PLL);
-       } else {
-               /* pull low */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
-       }
-}
-
 static void hdmi_phy_8960_powerup(struct hdmi_phy *phy,
                unsigned long int pixclock)
 {
@@ -511,7 +460,6 @@ static void hdmi_phy_8960_powerdown(struct hdmi_phy *phy)
 
 static const struct hdmi_phy_funcs hdmi_phy_8960_funcs = {
                .destroy = hdmi_phy_8960_destroy,
-               .reset = hdmi_phy_8960_reset,
                .powerup = hdmi_phy_8960_powerup,
                .powerdown = hdmi_phy_8960_powerdown,
 };
index 391433c1af7c1d04b824384cbd44470f351494f0..cb01421ae1e4ba9db3df0cdc0997e4d6591c2147 100644 (file)
@@ -29,37 +29,6 @@ static void hdmi_phy_8x60_destroy(struct hdmi_phy *phy)
        kfree(phy_8x60);
 }
 
-static void hdmi_phy_8x60_reset(struct hdmi_phy *phy)
-{
-       struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy);
-       struct hdmi *hdmi = phy_8x60->hdmi;
-       unsigned int val;
-
-       val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
-
-       if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
-               /* pull low */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val & ~HDMI_PHY_CTRL_SW_RESET);
-       } else {
-               /* pull high */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val | HDMI_PHY_CTRL_SW_RESET);
-       }
-
-       msleep(100);
-
-       if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
-               /* pull high */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val | HDMI_PHY_CTRL_SW_RESET);
-       } else {
-               /* pull low */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val & ~HDMI_PHY_CTRL_SW_RESET);
-       }
-}
-
 static void hdmi_phy_8x60_powerup(struct hdmi_phy *phy,
                unsigned long int pixclock)
 {
@@ -182,7 +151,6 @@ static void hdmi_phy_8x60_powerdown(struct hdmi_phy *phy)
 
 static const struct hdmi_phy_funcs hdmi_phy_8x60_funcs = {
                .destroy = hdmi_phy_8x60_destroy,
-               .reset = hdmi_phy_8x60_reset,
                .powerup = hdmi_phy_8x60_powerup,
                .powerdown = hdmi_phy_8x60_powerdown,
 };
index 59fa6cdacb2aa9bd9d4e6de52f470510ea140a31..56ab8917ee9a353a7d497c0231fd9d5c07e2f768 100644 (file)
@@ -19,7 +19,6 @@
 
 struct hdmi_phy_8x74 {
        struct hdmi_phy base;
-       struct hdmi *hdmi;
        void __iomem *mmio;
 };
 #define to_hdmi_phy_8x74(x) container_of(x, struct hdmi_phy_8x74, base)
@@ -41,59 +40,6 @@ static void hdmi_phy_8x74_destroy(struct hdmi_phy *phy)
        kfree(phy_8x74);
 }
 
-static void hdmi_phy_8x74_reset(struct hdmi_phy *phy)
-{
-       struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy);
-       struct hdmi *hdmi = phy_8x74->hdmi;
-       unsigned int val;
-
-       /* NOTE that HDMI_PHY_CTL is in core mmio, not phy mmio: */
-
-       val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
-
-       if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
-               /* pull low */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val & ~HDMI_PHY_CTRL_SW_RESET);
-       } else {
-               /* pull high */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val | HDMI_PHY_CTRL_SW_RESET);
-       }
-
-       if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
-               /* pull low */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
-       } else {
-               /* pull high */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val | HDMI_PHY_CTRL_SW_RESET_PLL);
-       }
-
-       msleep(100);
-
-       if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
-               /* pull high */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val | HDMI_PHY_CTRL_SW_RESET);
-       } else {
-               /* pull low */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val & ~HDMI_PHY_CTRL_SW_RESET);
-       }
-
-       if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
-               /* pull high */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val | HDMI_PHY_CTRL_SW_RESET_PLL);
-       } else {
-               /* pull low */
-               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
-                               val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
-       }
-}
-
 static void hdmi_phy_8x74_powerup(struct hdmi_phy *phy,
                unsigned long int pixclock)
 {
@@ -117,7 +63,6 @@ static void hdmi_phy_8x74_powerdown(struct hdmi_phy *phy)
 
 static const struct hdmi_phy_funcs hdmi_phy_8x74_funcs = {
                .destroy = hdmi_phy_8x74_destroy,
-               .reset = hdmi_phy_8x74_reset,
                .powerup = hdmi_phy_8x74_powerup,
                .powerdown = hdmi_phy_8x74_powerdown,
 };
@@ -138,8 +83,6 @@ struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi)
 
        phy->funcs = &hdmi_phy_8x74_funcs;
 
-       phy_8x74->hdmi = hdmi;
-
        /* for 8x74, the phy mmio is mapped separately: */
        phy_8x74->mmio = msm_ioremap(hdmi->pdev,
                        "phy_physical", "HDMI_8x74");
index 978c3f70872aa877ffb6001647926094a9630d19..2aa23b98f8aa5815b9c5d10031ca6531507f1b89 100644 (file)
@@ -8,19 +8,19 @@ 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            (  20915 bytes, from 2015-03-24 22:05:22)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2352 bytes, from 2015-04-12 15:02:42)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  35083 bytes, from 2015-04-12 15:04:03)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  22094 bytes, from 2015-05-12 12:45:23)
-- /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           (  29012 bytes, from 2015-05-12 12:45:23)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-12 12:45:23)
-
-Copyright (C) 2013 by the following authors:
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2576 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  36021 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  26057 bytes, from 2015-08-14 21:47:57)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  29154 bytes, from 2015-08-10 21:25:43)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-20 20:03:14)
+
+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
index 153fc487d683c7310f4b1b4bb9f1f748ff9f0016..74b86734fef547b0b066fa9cdc4bcec06d2fc875 100644 (file)
@@ -8,17 +8,17 @@ 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            (  20915 bytes, from 2015-03-24 22:05:22)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2352 bytes, from 2015-04-12 15:02:42)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  35083 bytes, from 2015-04-12 15:04:03)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  22094 bytes, from 2015-05-12 12:45:23)
-- /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           (  29012 bytes, from 2015-05-12 12:45:23)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-12 12:45:23)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2576 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  36021 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  26057 bytes, from 2015-08-14 21:47:57)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  29154 bytes, from 2015-08-10 21:25:43)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-20 20:03:14)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index c4bb9d9c7667e8453242fced07eae6d06c63bf74..6ac9aa165768da569e9ac1ea3bd5f36331c83fee 100644 (file)
@@ -334,13 +334,15 @@ static int mdp4_crtc_atomic_check(struct drm_crtc *crtc,
        return 0;
 }
 
-static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc)
+static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc,
+                                  struct drm_crtc_state *old_crtc_state)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        DBG("%s: begin", mdp4_crtc->name);
 }
 
-static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc)
+static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc,
+                                  struct drm_crtc_state *old_crtc_state)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        struct drm_device *dev = crtc->dev;
@@ -680,7 +682,5 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
        drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
        plane->crtc = crtc;
 
-       mdp4_plane_install_properties(plane, &crtc->base);
-
        return crtc;
 }
index 7369ee7f0c5544a6c44b9850e4ded92217da2596..5ed38cf548a1248a2e9188aa44ce9f488dba58aa 100644 (file)
 #include "msm_drv.h"
 #include "mdp4_kms.h"
 
-void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask)
+void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
+               uint32_t old_irqmask)
 {
+       mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_CLEAR,
+               irqmask ^ (irqmask & old_irqmask));
        mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_ENABLE, irqmask);
 }
 
@@ -68,9 +71,10 @@ irqreturn_t mdp4_irq(struct msm_kms *kms)
        struct drm_device *dev = mdp4_kms->dev;
        struct msm_drm_private *priv = dev->dev_private;
        unsigned int id;
-       uint32_t status;
+       uint32_t status, enable;
 
-       status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS);
+       enable = mdp4_read(mdp4_kms, REG_MDP4_INTR_ENABLE);
+       status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS) & enable;
        mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, status);
 
        VERB("status=%08x", status);
@@ -86,13 +90,22 @@ irqreturn_t mdp4_irq(struct msm_kms *kms)
 
 int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
 {
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+
+       mdp4_enable(mdp4_kms);
        mdp_update_vblank_mask(to_mdp_kms(kms),
                        mdp4_crtc_vblank(crtc), true);
+       mdp4_disable(mdp4_kms);
+
        return 0;
 }
 
 void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
 {
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+
+       mdp4_enable(mdp4_kms);
        mdp_update_vblank_mask(to_mdp_kms(kms),
                        mdp4_crtc_vblank(crtc), false);
+       mdp4_disable(mdp4_kms);
 }
index 531e4acc2a872f8263b1e124e3e801ff30521e7b..077f7521a971b7b6827ae77743f0fe5d19a9309b 100644 (file)
@@ -241,22 +241,37 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
 }
 
 #ifdef CONFIG_OF
-static struct drm_panel *detect_panel(struct drm_device *dev, const char *name)
+static struct drm_panel *detect_panel(struct drm_device *dev)
 {
-       struct device_node *n;
+       struct device_node *endpoint, *panel_node;
+       struct device_node *np = dev->dev->of_node;
        struct drm_panel *panel = NULL;
 
-       n = of_parse_phandle(dev->dev->of_node, name, 0);
-       if (n) {
-               panel = of_drm_find_panel(n);
-               if (!panel)
-                       panel = ERR_PTR(-EPROBE_DEFER);
+       endpoint = of_graph_get_next_endpoint(np, NULL);
+       if (!endpoint) {
+               dev_err(dev->dev, "no valid endpoint\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       panel_node = of_graph_get_remote_port_parent(endpoint);
+       if (!panel_node) {
+               dev_err(dev->dev, "no valid panel node\n");
+               of_node_put(endpoint);
+               return ERR_PTR(-ENODEV);
+       }
+
+       of_node_put(endpoint);
+
+       panel = of_drm_find_panel(panel_node);
+       if (!panel) {
+               of_node_put(panel_node);
+               return ERR_PTR(-EPROBE_DEFER);
        }
 
        return panel;
 }
 #else
-static struct drm_panel *detect_panel(struct drm_device *dev, const char *name)
+static struct drm_panel *detect_panel(struct drm_device *dev)
 {
        // ??? maybe use a module param to specify which panel is attached?
 }
@@ -294,7 +309,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
         * Setup the LCDC/LVDS path: RGB2 -> DMA_P -> LCDC -> LVDS:
         */
 
-       panel = detect_panel(dev, "qcom,lvds-panel");
+       panel = detect_panel(dev);
        if (IS_ERR(panel)) {
                ret = PTR_ERR(panel);
                dev_err(dev->dev, "failed to detect LVDS panel: %d\n", ret);
@@ -527,6 +542,11 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
                goto fail;
        }
 
+       dev->mode_config.min_width = 0;
+       dev->mode_config.min_height = 0;
+       dev->mode_config.max_width = 2048;
+       dev->mode_config.max_height = 2048;
+
        return kms;
 
 fail:
index c1ecb9d6bdefecda24ba9ea308eb8a3430f6e1fb..8a7f6e1e2bca9dd0ba3205995a374516c2d53350 100644 (file)
@@ -167,7 +167,8 @@ static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer,
 int mdp4_disable(struct mdp4_kms *mdp4_kms);
 int mdp4_enable(struct mdp4_kms *mdp4_kms);
 
-void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask);
+void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
+               uint32_t old_irqmask);
 void mdp4_irq_preinstall(struct msm_kms *kms);
 int mdp4_irq_postinstall(struct msm_kms *kms);
 void mdp4_irq_uninstall(struct msm_kms *kms);
@@ -175,29 +176,24 @@ irqreturn_t mdp4_irq(struct msm_kms *kms);
 int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 
-static inline bool pipe_supports_yuv(enum mdp4_pipe pipe)
+static inline uint32_t mdp4_pipe_caps(enum mdp4_pipe pipe)
 {
        switch (pipe) {
        case VG1:
        case VG2:
        case VG3:
        case VG4:
-               return true;
+               return MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+                               MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC;
+       case RGB1:
+       case RGB2:
+       case RGB3:
+               return MDP_PIPE_CAP_SCALE;
        default:
-               return false;
+               return 0;
        }
 }
 
-static inline
-uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats,
-               uint32_t max_formats)
-{
-       return mdp_get_formats(pixel_formats, max_formats,
-                               !pipe_supports_yuv(pipe_id));
-}
-
-void mdp4_plane_install_properties(struct drm_plane *plane,
-               struct drm_mode_object *obj);
 enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane);
 struct drm_plane *mdp4_plane_init(struct drm_device *dev,
                enum mdp4_pipe pipe_id, bool private_plane);
index c04843376c540b29e98ecd22471b3c1132d8c854..4cd6e721aa0a3a51f4c206ab8234885d97b8d7e5 100644 (file)
@@ -346,8 +346,10 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
 
        mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
 
-       if (panel)
+       if (panel) {
                drm_panel_disable(panel);
+               drm_panel_unprepare(panel);
+       }
 
        /*
         * Wait for a vsync so we know the ENABLE=0 latched before
@@ -412,8 +414,10 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
        if (ret)
                dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
 
-       if (panel)
+       if (panel) {
+               drm_panel_prepare(panel);
                drm_panel_enable(panel);
+       }
 
        setup_phy(encoder);
 
index 0d1dbb73793355043d514f2c4239e16386671e00..e9dee367b597e0761f874ce62fde57ad2f8b90fb 100644 (file)
@@ -26,6 +26,7 @@ struct mdp4_plane {
 
        enum mdp4_pipe pipe;
 
+       uint32_t caps;
        uint32_t nformats;
        uint32_t formats[32];
 
@@ -74,7 +75,7 @@ static void mdp4_plane_destroy(struct drm_plane *plane)
 }
 
 /* helper to install properties which are common to planes and crtcs */
-void mdp4_plane_install_properties(struct drm_plane *plane,
+static void mdp4_plane_install_properties(struct drm_plane *plane,
                struct drm_mode_object *obj)
 {
        // XXX
@@ -220,13 +221,15 @@ static int mdp4_plane_mode_set(struct drm_plane *plane,
        uint32_t op_mode = 0;
        uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT;
        uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT;
-       enum mdp4_frame_format frame_type = mdp4_get_frame_format(fb);
+       enum mdp4_frame_format frame_type;
 
        if (!(crtc && fb)) {
                DBG("%s: disabled!", mdp4_plane->name);
                return 0;
        }
 
+       frame_type = mdp4_get_frame_format(fb);
+
        /* src values are in Q16 fixed point, convert to integer: */
        src_x = src_x >> 16;
        src_y = src_y >> 16;
@@ -380,9 +383,11 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
 
        mdp4_plane->pipe = pipe_id;
        mdp4_plane->name = pipe_names[pipe_id];
+       mdp4_plane->caps = mdp4_pipe_caps(pipe_id);
 
-       mdp4_plane->nformats = mdp4_get_formats(pipe_id, mdp4_plane->formats,
-                       ARRAY_SIZE(mdp4_plane->formats));
+       mdp4_plane->nformats = mdp_get_formats(mdp4_plane->formats,
+                       ARRAY_SIZE(mdp4_plane->formats),
+                       !pipe_supports_yuv(mdp4_plane->caps));
 
        type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
        ret = drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
index 50e17527e2e56f80bda717d1588a8eda1891e0f7..3469f50d55905c01c8f7c687747e0a510dd203b1 100644 (file)
@@ -8,17 +8,17 @@ 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            (  20915 bytes, from 2015-03-24 22:05:22)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2352 bytes, from 2015-04-12 15:02:42)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  35083 bytes, from 2015-04-12 15:04:03)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  22094 bytes, from 2015-05-12 12:45:23)
-- /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           (  29012 bytes, from 2015-05-12 12:45:23)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-12 12:45:23)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2576 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  36021 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  26057 bytes, from 2015-08-14 21:47:57)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  29154 bytes, from 2015-08-10 21:25:43)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-20 20:03:14)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -381,49 +381,49 @@ static inline uint32_t REG_MDP5_CTL_LAYER(uint32_t i0, uint32_t i1) { return 0x0
 static inline uint32_t REG_MDP5_CTL_LAYER_REG(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER(i1); }
 #define MDP5_CTL_LAYER_REG_VIG0__MASK                          0x00000007
 #define MDP5_CTL_LAYER_REG_VIG0__SHIFT                         0
-static inline uint32_t MDP5_CTL_LAYER_REG_VIG0(enum mdp_mixer_stage_id val)
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG0(uint32_t val)
 {
        return ((val) << MDP5_CTL_LAYER_REG_VIG0__SHIFT) & MDP5_CTL_LAYER_REG_VIG0__MASK;
 }
 #define MDP5_CTL_LAYER_REG_VIG1__MASK                          0x00000038
 #define MDP5_CTL_LAYER_REG_VIG1__SHIFT                         3
-static inline uint32_t MDP5_CTL_LAYER_REG_VIG1(enum mdp_mixer_stage_id val)
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG1(uint32_t val)
 {
        return ((val) << MDP5_CTL_LAYER_REG_VIG1__SHIFT) & MDP5_CTL_LAYER_REG_VIG1__MASK;
 }
 #define MDP5_CTL_LAYER_REG_VIG2__MASK                          0x000001c0
 #define MDP5_CTL_LAYER_REG_VIG2__SHIFT                         6
-static inline uint32_t MDP5_CTL_LAYER_REG_VIG2(enum mdp_mixer_stage_id val)
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG2(uint32_t val)
 {
        return ((val) << MDP5_CTL_LAYER_REG_VIG2__SHIFT) & MDP5_CTL_LAYER_REG_VIG2__MASK;
 }
 #define MDP5_CTL_LAYER_REG_RGB0__MASK                          0x00000e00
 #define MDP5_CTL_LAYER_REG_RGB0__SHIFT                         9
-static inline uint32_t MDP5_CTL_LAYER_REG_RGB0(enum mdp_mixer_stage_id val)
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB0(uint32_t val)
 {
        return ((val) << MDP5_CTL_LAYER_REG_RGB0__SHIFT) & MDP5_CTL_LAYER_REG_RGB0__MASK;
 }
 #define MDP5_CTL_LAYER_REG_RGB1__MASK                          0x00007000
 #define MDP5_CTL_LAYER_REG_RGB1__SHIFT                         12
-static inline uint32_t MDP5_CTL_LAYER_REG_RGB1(enum mdp_mixer_stage_id val)
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB1(uint32_t val)
 {
        return ((val) << MDP5_CTL_LAYER_REG_RGB1__SHIFT) & MDP5_CTL_LAYER_REG_RGB1__MASK;
 }
 #define MDP5_CTL_LAYER_REG_RGB2__MASK                          0x00038000
 #define MDP5_CTL_LAYER_REG_RGB2__SHIFT                         15
-static inline uint32_t MDP5_CTL_LAYER_REG_RGB2(enum mdp_mixer_stage_id val)
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB2(uint32_t val)
 {
        return ((val) << MDP5_CTL_LAYER_REG_RGB2__SHIFT) & MDP5_CTL_LAYER_REG_RGB2__MASK;
 }
 #define MDP5_CTL_LAYER_REG_DMA0__MASK                          0x001c0000
 #define MDP5_CTL_LAYER_REG_DMA0__SHIFT                         18
-static inline uint32_t MDP5_CTL_LAYER_REG_DMA0(enum mdp_mixer_stage_id val)
+static inline uint32_t MDP5_CTL_LAYER_REG_DMA0(uint32_t val)
 {
        return ((val) << MDP5_CTL_LAYER_REG_DMA0__SHIFT) & MDP5_CTL_LAYER_REG_DMA0__MASK;
 }
 #define MDP5_CTL_LAYER_REG_DMA1__MASK                          0x00e00000
 #define MDP5_CTL_LAYER_REG_DMA1__SHIFT                         21
-static inline uint32_t MDP5_CTL_LAYER_REG_DMA1(enum mdp_mixer_stage_id val)
+static inline uint32_t MDP5_CTL_LAYER_REG_DMA1(uint32_t val)
 {
        return ((val) << MDP5_CTL_LAYER_REG_DMA1__SHIFT) & MDP5_CTL_LAYER_REG_DMA1__MASK;
 }
@@ -431,13 +431,13 @@ static inline uint32_t MDP5_CTL_LAYER_REG_DMA1(enum mdp_mixer_stage_id val)
 #define MDP5_CTL_LAYER_REG_CURSOR_OUT                          0x02000000
 #define MDP5_CTL_LAYER_REG_VIG3__MASK                          0x1c000000
 #define MDP5_CTL_LAYER_REG_VIG3__SHIFT                         26
-static inline uint32_t MDP5_CTL_LAYER_REG_VIG3(enum mdp_mixer_stage_id val)
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG3(uint32_t val)
 {
        return ((val) << MDP5_CTL_LAYER_REG_VIG3__SHIFT) & MDP5_CTL_LAYER_REG_VIG3__MASK;
 }
 #define MDP5_CTL_LAYER_REG_RGB3__MASK                          0xe0000000
 #define MDP5_CTL_LAYER_REG_RGB3__SHIFT                         29
-static inline uint32_t MDP5_CTL_LAYER_REG_RGB3(enum mdp_mixer_stage_id val)
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB3(uint32_t val)
 {
        return ((val) << MDP5_CTL_LAYER_REG_RGB3__SHIFT) & MDP5_CTL_LAYER_REG_RGB3__MASK;
 }
@@ -499,6 +499,44 @@ static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000001c + __o
 
 static inline uint32_t REG_MDP5_CTL_PACK_3D(uint32_t i0) { return 0x00000020 + __offset_CTL(i0); }
 
+static inline uint32_t __offset_LAYER_EXT(uint32_t idx)
+{
+       switch (idx) {
+               case 0: return 0x00000040;
+               case 1: return 0x00000044;
+               case 2: return 0x00000048;
+               case 3: return 0x0000004c;
+               case 4: return 0x00000050;
+               case 5: return 0x00000054;
+               default: return INVALID_IDX(idx);
+       }
+}
+static inline uint32_t REG_MDP5_CTL_LAYER_EXT(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER_EXT(i1); }
+
+static inline uint32_t REG_MDP5_CTL_LAYER_EXT_REG(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER_EXT(i1); }
+#define MDP5_CTL_LAYER_EXT_REG_VIG0_BIT3                       0x00000001
+#define MDP5_CTL_LAYER_EXT_REG_VIG1_BIT3                       0x00000004
+#define MDP5_CTL_LAYER_EXT_REG_VIG2_BIT3                       0x00000010
+#define MDP5_CTL_LAYER_EXT_REG_VIG3_BIT3                       0x00000040
+#define MDP5_CTL_LAYER_EXT_REG_RGB0_BIT3                       0x00000100
+#define MDP5_CTL_LAYER_EXT_REG_RGB1_BIT3                       0x00000400
+#define MDP5_CTL_LAYER_EXT_REG_RGB2_BIT3                       0x00001000
+#define MDP5_CTL_LAYER_EXT_REG_RGB3_BIT3                       0x00004000
+#define MDP5_CTL_LAYER_EXT_REG_DMA0_BIT3                       0x00010000
+#define MDP5_CTL_LAYER_EXT_REG_DMA1_BIT3                       0x00040000
+#define MDP5_CTL_LAYER_EXT_REG_CURSOR0__MASK                   0x00f00000
+#define MDP5_CTL_LAYER_EXT_REG_CURSOR0__SHIFT                  20
+static inline uint32_t MDP5_CTL_LAYER_EXT_REG_CURSOR0(enum mdp_mixer_stage_id val)
+{
+       return ((val) << MDP5_CTL_LAYER_EXT_REG_CURSOR0__SHIFT) & MDP5_CTL_LAYER_EXT_REG_CURSOR0__MASK;
+}
+#define MDP5_CTL_LAYER_EXT_REG_CURSOR1__MASK                   0x3c000000
+#define MDP5_CTL_LAYER_EXT_REG_CURSOR1__SHIFT                  26
+static inline uint32_t MDP5_CTL_LAYER_EXT_REG_CURSOR1(enum mdp_mixer_stage_id val)
+{
+       return ((val) << MDP5_CTL_LAYER_EXT_REG_CURSOR1__SHIFT) & MDP5_CTL_LAYER_EXT_REG_CURSOR1__MASK;
+}
+
 static inline uint32_t __offset_PIPE(enum mdp5_pipe idx)
 {
        switch (idx) {
@@ -803,11 +841,11 @@ static inline uint32_t MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val)
 }
 #define MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT                      0x00020000
 #define MDP5_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB                  0x00040000
-#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK                  0x00180000
-#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT                 19
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(enum mdp_fetch_type val)
+#define MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__MASK                  0x00180000
+#define MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__SHIFT                 19
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(enum mdp_fetch_type val)
 {
-       return ((val) << MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT) & MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK;
+       return ((val) << MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__SHIFT) & MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__MASK;
 }
 #define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK                 0x01800000
 #define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT                        23
@@ -897,41 +935,41 @@ static inline uint32_t MDP5_PIPE_DECIMATION_HORZ(uint32_t val)
 static inline uint32_t REG_MDP5_PIPE_SCALE_CONFIG(enum mdp5_pipe i0) { return 0x00000204 + __offset_PIPE(i0); }
 #define MDP5_PIPE_SCALE_CONFIG_SCALEX_EN                       0x00000001
 #define MDP5_PIPE_SCALE_CONFIG_SCALEY_EN                       0x00000002
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__MASK         0x00000300
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__SHIFT                8
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(enum mdp5_scale_filter val)
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__MASK      0x00000300
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__SHIFT     8
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(enum mdp5_scale_filter val)
 {
-       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__MASK;
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__MASK;
 }
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__MASK         0x00000c00
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__SHIFT                10
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(enum mdp5_scale_filter val)
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__MASK      0x00000c00
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__SHIFT     10
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(enum mdp5_scale_filter val)
 {
-       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__MASK;
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__MASK;
 }
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__MASK          0x00003000
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__SHIFT         12
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(enum mdp5_scale_filter val)
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__MASK    0x00003000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__SHIFT   12
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(enum mdp5_scale_filter val)
 {
-       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__MASK;
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__MASK;
 }
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__MASK          0x0000c000
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__SHIFT         14
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(enum mdp5_scale_filter val)
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__MASK    0x0000c000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__SHIFT   14
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(enum mdp5_scale_filter val)
 {
-       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__MASK;
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__MASK;
 }
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__MASK         0x00030000
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__SHIFT                16
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(enum mdp5_scale_filter val)
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__MASK      0x00030000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__SHIFT     16
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(enum mdp5_scale_filter val)
 {
-       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__MASK;
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__MASK;
 }
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__MASK         0x000c0000
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__SHIFT                18
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(enum mdp5_scale_filter val)
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__MASK      0x000c0000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__SHIFT     18
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(enum mdp5_scale_filter val)
 {
-       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__MASK;
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__MASK;
 }
 
 static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00000210 + __offset_PIPE(i0); }
@@ -984,9 +1022,22 @@ static inline uint32_t REG_MDP5_LM_BORDER_COLOR_0(uint32_t i0) { return 0x000000
 
 static inline uint32_t REG_MDP5_LM_BORDER_COLOR_1(uint32_t i0) { return 0x00000010 + __offset_LM(i0); }
 
-static inline uint32_t REG_MDP5_LM_BLEND(uint32_t i0, uint32_t i1) { return 0x00000020 + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t __offset_BLEND(uint32_t idx)
+{
+       switch (idx) {
+               case 0: return 0x00000020;
+               case 1: return 0x00000050;
+               case 2: return 0x00000080;
+               case 3: return 0x000000b0;
+               case 4: return 0x00000230;
+               case 5: return 0x00000260;
+               case 6: return 0x00000290;
+               default: return INVALID_IDX(idx);
+       }
+}
+static inline uint32_t REG_MDP5_LM_BLEND(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_LM(i0) + __offset_BLEND(i1); }
 
-static inline uint32_t REG_MDP5_LM_BLEND_OP_MODE(uint32_t i0, uint32_t i1) { return 0x00000020 + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_OP_MODE(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_LM(i0) + __offset_BLEND(i1); }
 #define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK                   0x00000003
 #define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT                  0
 static inline uint32_t MDP5_LM_BLEND_OP_MODE_FG_ALPHA(enum mdp_alpha_type val)
@@ -1008,25 +1059,25 @@ static inline uint32_t MDP5_LM_BLEND_OP_MODE_BG_ALPHA(enum mdp_alpha_type val)
 #define MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA                 0x00001000
 #define MDP5_LM_BLEND_OP_MODE_BG_TRANSP_EN                     0x00002000
 
-static inline uint32_t REG_MDP5_LM_BLEND_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000024 + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000004 + __offset_LM(i0) + __offset_BLEND(i1); }
 
-static inline uint32_t REG_MDP5_LM_BLEND_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000028 + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000008 + __offset_LM(i0) + __offset_BLEND(i1); }
 
-static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000002c + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000000c + __offset_LM(i0) + __offset_BLEND(i1); }
 
-static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000030 + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000010 + __offset_LM(i0) + __offset_BLEND(i1); }
 
-static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000034 + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000014 + __offset_LM(i0) + __offset_BLEND(i1); }
 
-static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000038 + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000018 + __offset_LM(i0) + __offset_BLEND(i1); }
 
-static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000003c + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000001c + __offset_LM(i0) + __offset_BLEND(i1); }
 
-static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000040 + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000020 + __offset_LM(i0) + __offset_BLEND(i1); }
 
-static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000044 + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000024 + __offset_LM(i0) + __offset_BLEND(i1); }
 
-static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000048 + __offset_LM(i0) + 0x30*i1; }
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000028 + __offset_LM(i0) + __offset_BLEND(i1); }
 
 static inline uint32_t REG_MDP5_LM_CURSOR_IMG_SIZE(uint32_t i0) { return 0x000000e0 + __offset_LM(i0); }
 #define MDP5_LM_CURSOR_IMG_SIZE_SRC_W__MASK                    0x0000ffff
@@ -1260,6 +1311,13 @@ static inline uint32_t REG_MDP5_PP_FBC_LOSSY_MODE(uint32_t i0) { return 0x000000
 static inline uint32_t __offset_WB(uint32_t idx)
 {
        switch (idx) {
+#if 0  /* TEMPORARY until patch that adds wb.base[] is merged */
+               case 0: return (mdp5_cfg->wb.base[0]);
+               case 1: return (mdp5_cfg->wb.base[1]);
+               case 2: return (mdp5_cfg->wb.base[2]);
+               case 3: return (mdp5_cfg->wb.base[3]);
+               case 4: return (mdp5_cfg->wb.base[4]);
+#endif
                default: return INVALID_IDX(idx);
        }
 }
index 8b9a7931b1624365dac35be9ca492b04967487b0..a1e26f23c7cca53a19f2ad557a1cdb01b4c4a646 100644 (file)
@@ -22,7 +22,76 @@ struct mdp5_cfg_handler {
 /* mdp5_cfg must be exposed (used in mdp5.xml.h) */
 const struct mdp5_cfg_hw *mdp5_cfg = NULL;
 
-const struct mdp5_cfg_hw msm8x74_config = {
+const struct mdp5_cfg_hw msm8x74v1_config = {
+       .name = "msm8x74v1",
+       .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,
+               .base = { 0x01200, 0x01600, 0x01a00 },
+               .caps = MDP_PIPE_CAP_HFLIP |
+                       MDP_PIPE_CAP_VFLIP |
+                       MDP_PIPE_CAP_SCALE |
+                       MDP_PIPE_CAP_CSC   |
+                       0,
+       },
+       .pipe_rgb = {
+               .count = 3,
+               .base = { 0x01e00, 0x02200, 0x02600 },
+               .caps = MDP_PIPE_CAP_HFLIP |
+                       MDP_PIPE_CAP_VFLIP |
+                       MDP_PIPE_CAP_SCALE |
+                       0,
+       },
+       .pipe_dma = {
+               .count = 2,
+               .base = { 0x02a00, 0x02e00 },
+               .caps = MDP_PIPE_CAP_HFLIP |
+                       MDP_PIPE_CAP_VFLIP |
+                       0,
+       },
+       .lm = {
+               .count = 5,
+               .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 },
+               .nb_stages = 5,
+       },
+       .dspp = {
+               .count = 3,
+               .base = { 0x04600, 0x04a00, 0x04e00 },
+       },
+       .pp = {
+               .count = 3,
+               .base = { 0x21b00, 0x21c00, 0x21d00 },
+       },
+       .intf = {
+               .base = { 0x21100, 0x21300, 0x21500, 0x21700 },
+               .connect = {
+                       [0] = INTF_eDP,
+                       [1] = INTF_DSI,
+                       [2] = INTF_DSI,
+                       [3] = INTF_HDMI,
+               },
+       },
+       .max_clk = 200000000,
+};
+
+const struct mdp5_cfg_hw msm8x74v2_config = {
        .name = "msm8x74",
        .mdp = {
                .count = 1,
@@ -45,19 +114,27 @@ const struct mdp5_cfg_hw msm8x74_config = {
        .pipe_vig = {
                .count = 3,
                .base = { 0x01200, 0x01600, 0x01a00 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+                               MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
+                               MDP_PIPE_CAP_DECIMATION,
        },
        .pipe_rgb = {
                .count = 3,
                .base = { 0x01e00, 0x02200, 0x02600 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+                               MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
        },
        .pipe_dma = {
                .count = 2,
                .base = { 0x02a00, 0x02e00 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
        },
        .lm = {
                .count = 5,
                .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 },
                .nb_stages = 5,
+               .max_width = 2048,
+               .max_height = 0xFFFF,
        },
        .dspp = {
                .count = 3,
@@ -65,7 +142,7 @@ const struct mdp5_cfg_hw msm8x74_config = {
        },
        .ad = {
                .count = 2,
-               .base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */
+               .base = { 0x13100, 0x13300 },
        },
        .pp = {
                .count = 3,
@@ -113,19 +190,27 @@ const struct mdp5_cfg_hw apq8084_config = {
        .pipe_vig = {
                .count = 4,
                .base = { 0x01200, 0x01600, 0x01a00, 0x01e00 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+                               MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
+                               MDP_PIPE_CAP_DECIMATION,
        },
        .pipe_rgb = {
                .count = 4,
                .base = { 0x02200, 0x02600, 0x02a00, 0x02e00 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+                               MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
        },
        .pipe_dma = {
                .count = 2,
                .base = { 0x03200, 0x03600 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
        },
        .lm = {
                .count = 6,
                .base = { 0x03a00, 0x03e00, 0x04200, 0x04600, 0x04a00, 0x04e00 },
                .nb_stages = 5,
+               .max_width = 2048,
+               .max_height = 0xFFFF,
        },
        .dspp = {
                .count = 4,
@@ -174,19 +259,27 @@ const struct mdp5_cfg_hw msm8x16_config = {
        .pipe_vig = {
                .count = 1,
                .base = { 0x05000 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+                               MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
+                               MDP_PIPE_CAP_DECIMATION,
        },
        .pipe_rgb = {
                .count = 2,
                .base = { 0x15000, 0x17000 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+                               MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
        },
        .pipe_dma = {
                .count = 1,
                .base = { 0x25000 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
        },
        .lm = {
                .count = 2, /* LM0 and LM3 */
                .base = { 0x45000, 0x48000 },
                .nb_stages = 5,
+               .max_width = 2048,
+               .max_height = 0xFFFF,
        },
        .dspp = {
                .count = 1,
@@ -203,14 +296,91 @@ const struct mdp5_cfg_hw msm8x16_config = {
        .max_clk = 320000000,
 };
 
+const struct mdp5_cfg_hw msm8x94_config = {
+       .name = "msm8x94",
+       .mdp = {
+               .count = 1,
+               .base = { 0x01000 },
+       },
+       .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(23, 0),    /* first 24 MMBs */
+               .reserved = {
+                        [1] = 1,  [4] = 1,  [7] = 1, [19] = 1,
+                       [16] = 5, [17] = 5, [18] = 5, [22] = 5,
+               },
+       },
+       .ctl = {
+               .count = 5,
+               .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 },
+               .flush_hw_mask = 0xf0ffffff,
+       },
+       .pipe_vig = {
+               .count = 4,
+               .base = { 0x05000, 0x07000, 0x09000, 0x0b000 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+                               MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
+                               MDP_PIPE_CAP_DECIMATION,
+       },
+       .pipe_rgb = {
+               .count = 4,
+               .base = { 0x15000, 0x17000, 0x19000, 0x1b000 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+                               MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
+       },
+       .pipe_dma = {
+               .count = 2,
+               .base = { 0x25000, 0x27000 },
+               .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
+       },
+       .lm = {
+               .count = 6,
+               .base = { 0x45000, 0x46000, 0x47000, 0x48000, 0x49000, 0x4a000 },
+               .nb_stages = 8,
+               .max_width = 2048,
+               .max_height = 0xFFFF,
+       },
+       .dspp = {
+               .count = 4,
+               .base = { 0x55000, 0x57000, 0x59000, 0x5b000 },
+
+       },
+       .ad = {
+               .count = 3,
+               .base = { 0x79000, 0x79800, 0x7a000 },
+       },
+       .pp = {
+               .count = 4,
+               .base = { 0x71000, 0x71800, 0x72000, 0x72800 },
+       },
+       .intf = {
+               .base = { 0x6b000, 0x6b800, 0x6c000, 0x6c800, 0x6d000 },
+               .connect = {
+                       [0] = INTF_DISABLED,
+                       [1] = INTF_DSI,
+                       [2] = INTF_DSI,
+                       [3] = INTF_HDMI,
+               },
+       },
+       .max_clk = 320000000,
+};
+
 static const struct mdp5_cfg_handler cfg_handlers[] = {
-       { .revision = 0, .config = { .hw = &msm8x74_config } },
-       { .revision = 2, .config = { .hw = &msm8x74_config } },
+       { .revision = 0, .config = { .hw = &msm8x74v1_config } },
+       { .revision = 2, .config = { .hw = &msm8x74v2_config } },
        { .revision = 3, .config = { .hw = &apq8084_config } },
        { .revision = 6, .config = { .hw = &msm8x16_config } },
+       { .revision = 9, .config = { .hw = &msm8x94_config } },
 };
 
-
 static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);
 
 const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler)
index 69349abe59f2a4a614a9a9379b5c26f232087a3c..efb918d9f68bf4b265fc480bb069594a0bfda540 100644 (file)
@@ -42,6 +42,13 @@ struct mdp5_sub_block {
 struct mdp5_lm_block {
        MDP5_SUB_BLOCK_DEFINITION;
        uint32_t nb_stages;             /* number of stages per blender */
+       uint32_t max_width;             /* Maximum output resolution */
+       uint32_t max_height;
+};
+
+struct mdp5_pipe_block {
+       MDP5_SUB_BLOCK_DEFINITION;
+       uint32_t caps;                  /* pipe capabilities */
 };
 
 struct mdp5_ctl_block {
@@ -70,9 +77,9 @@ struct mdp5_cfg_hw {
        struct mdp5_sub_block mdp;
        struct mdp5_smp_block smp;
        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_pipe_block pipe_vig;
+       struct mdp5_pipe_block pipe_rgb;
+       struct mdp5_pipe_block pipe_dma;
        struct mdp5_lm_block  lm;
        struct mdp5_sub_block dspp;
        struct mdp5_sub_block ad;
index ee31b16fe7eae2366ad2805439862dea3594acbb..8e6c9b598a57e0e1a73faf625d04ec684ffbc12f 100644 (file)
@@ -21,6 +21,8 @@ struct mdp5_cmd_encoder {
        struct mdp5_interface intf;
        bool enabled;
        uint32_t bsc;
+
+       struct mdp5_ctl *ctl;
 };
 #define to_mdp5_cmd_encoder(x) container_of(x, struct mdp5_cmd_encoder, base)
 
@@ -210,13 +212,14 @@ static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
                        mode->vsync_end, mode->vtotal,
                        mode->type, mode->flags);
        pingpong_tearcheck_setup(encoder, mode);
-       mdp5_crtc_set_intf(encoder->crtc, &mdp5_cmd_enc->intf);
+       mdp5_crtc_set_pipeline(encoder->crtc, &mdp5_cmd_enc->intf,
+                               mdp5_cmd_enc->ctl);
 }
 
 static void mdp5_cmd_encoder_disable(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_ctl *ctl = mdp5_cmd_enc->ctl;
        struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
 
        if (WARN_ON(!mdp5_cmd_enc->enabled))
@@ -235,7 +238,7 @@ static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
 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_ctl *ctl = mdp5_cmd_enc->ctl;
        struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
 
        if (WARN_ON(mdp5_cmd_enc->enabled))
@@ -300,7 +303,7 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
 
 /* initialize command mode encoder */
 struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
-                               struct mdp5_interface *intf)
+                       struct mdp5_interface *intf, struct mdp5_ctl *ctl)
 {
        struct drm_encoder *encoder = NULL;
        struct mdp5_cmd_encoder *mdp5_cmd_enc;
@@ -320,6 +323,7 @@ struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
 
        memcpy(&mdp5_cmd_enc->intf, intf, sizeof(mdp5_cmd_enc->intf));
        encoder = &mdp5_cmd_enc->base;
+       mdp5_cmd_enc->ctl = ctl;
 
        drm_encoder_init(dev, encoder, &mdp5_cmd_encoder_funcs,
                        DRM_MODE_ENCODER_DSI);
index dea3d2e559b1cdf80c04cb35ca1fc3ae61ba3814..7f9f4ac88029c4cf6f7b46ae410478f2a5697e75 100644 (file)
@@ -160,8 +160,7 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
 
        if (mdp5_crtc->ctl && !crtc->state->enable) {
                /* set STAGE_UNUSED for all layers */
-               mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000);
-               mdp5_ctl_release(mdp5_crtc->ctl);
+               mdp5_ctl_blend(mdp5_crtc->ctl, NULL, 0, 0);
                mdp5_crtc->ctl = NULL;
        }
 }
@@ -196,13 +195,9 @@ static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc,
 /*
  * blend_setup() - blend all the planes of a CRTC
  *
- * When border is enabled, the border color will ALWAYS be the base layer.
- * Therefore, the first plane (private RGB pipe) will start at STAGE0.
- * If disabled, the first plane starts at STAGE_BASE.
- *
- * Note:
- * Border is not enabled here because the private plane is exactly
- * the CRTC resolution.
+ * If no base layer is available, border will be enabled as the base layer.
+ * Otherwise all layers will be blended based on their stage calculated
+ * in mdp5_crtc_atomic_check.
  */
 static void blend_setup(struct drm_crtc *crtc)
 {
@@ -210,9 +205,14 @@ static void blend_setup(struct drm_crtc *crtc)
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
        struct drm_plane *plane;
        const struct mdp5_cfg_hw *hw_cfg;
-       uint32_t lm = mdp5_crtc->lm, blend_cfg = 0;
+       struct mdp5_plane_state *pstate, *pstates[STAGE_MAX + 1] = {NULL};
+       const struct mdp_format *format;
+       uint32_t lm = mdp5_crtc->lm;
+       uint32_t blend_op, fg_alpha, bg_alpha, ctl_blend_flags = 0;
        unsigned long flags;
-#define blender(stage) ((stage) - STAGE_BASE)
+       uint8_t stage[STAGE_MAX + 1];
+       int i, plane_cnt = 0;
+#define blender(stage) ((stage) - STAGE0)
 
        hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
 
@@ -222,33 +222,73 @@ static void blend_setup(struct drm_crtc *crtc)
        if (!mdp5_crtc->ctl)
                goto out;
 
+       /* Collect all plane information */
        drm_atomic_crtc_for_each_plane(plane, crtc) {
-               enum mdp_mixer_stage_id stage =
-                       to_mdp5_plane_state(plane->state)->stage;
+               pstate = to_mdp5_plane_state(plane->state);
+               pstates[pstate->stage] = pstate;
+               stage[pstate->stage] = mdp5_plane_pipe(plane);
+               plane_cnt++;
+       }
 
-               /*
-                * Note: This cannot happen with current implementation but
-                * we need to check this condition once z property is added
-                */
-               BUG_ON(stage > hw_cfg->lm.nb_stages);
+       /*
+       * If there is no base layer, enable border color.
+       * Although it's not possbile in current blend logic,
+       * put it here as a reminder.
+       */
+       if (!pstates[STAGE_BASE] && plane_cnt) {
+               ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT;
+               DBG("Border Color is enabled");
+       }
 
-               /* LM */
-               mdp5_write(mdp5_kms,
-                               REG_MDP5_LM_BLEND_OP_MODE(lm, blender(stage)),
-                               MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
-                               MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST));
+       /* The reset for blending */
+       for (i = STAGE0; i <= STAGE_MAX; i++) {
+               if (!pstates[i])
+                       continue;
+
+               format = to_mdp_format(
+                       msm_framebuffer_format(pstates[i]->base.fb));
+               plane = pstates[i]->base.plane;
+               blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
+                       MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST);
+               fg_alpha = pstates[i]->alpha;
+               bg_alpha = 0xFF - pstates[i]->alpha;
+               DBG("Stage %d fg_alpha %x bg_alpha %x", i, fg_alpha, bg_alpha);
+
+               if (format->alpha_enable && pstates[i]->premultiplied) {
+                       blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
+                               MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL);
+                       if (fg_alpha != 0xff) {
+                               bg_alpha = fg_alpha;
+                               blend_op |=
+                                       MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA |
+                                       MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA;
+                       } else {
+                               blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA;
+                       }
+               } else if (format->alpha_enable) {
+                       blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_PIXEL) |
+                               MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL);
+                       if (fg_alpha != 0xff) {
+                               bg_alpha = fg_alpha;
+                               blend_op |=
+                                      MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA |
+                                      MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA |
+                                      MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA |
+                                      MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA;
+                       } else {
+                               blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA;
+                       }
+               }
+
+               mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(lm,
+                               blender(i)), blend_op);
                mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(lm,
-                               blender(stage)), 0xff);
+                               blender(i)), fg_alpha);
                mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm,
-                               blender(stage)), 0x00);
-               /* CTL */
-               blend_cfg |= mdp_ctl_blend_mask(mdp5_plane_pipe(plane), stage);
-               DBG("%s: blending pipe %s on stage=%d", mdp5_crtc->name,
-                               pipe2name(mdp5_plane_pipe(plane)), stage);
+                               blender(i)), bg_alpha);
        }
 
-       DBG("%s: lm%d: blend config = 0x%08x", mdp5_crtc->name, lm, blend_cfg);
-       mdp5_ctl_blend(mdp5_crtc->ctl, lm, blend_cfg);
+       mdp5_ctl_blend(mdp5_crtc->ctl, stage, plane_cnt, ctl_blend_flags);
 
 out:
        spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
@@ -339,25 +379,19 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
        struct drm_plane *plane;
        struct drm_device *dev = crtc->dev;
-       struct plane_state pstates[STAGE3 + 1];
+       struct plane_state pstates[STAGE_MAX + 1];
+       const struct mdp5_cfg_hw *hw_cfg;
        int cnt = 0, i;
 
        DBG("%s: check", mdp5_crtc->name);
 
-       /* request a free CTL, if none is already allocated for this CRTC */
-       if (state->enable && !mdp5_crtc->ctl) {
-               mdp5_crtc->ctl = mdp5_ctlm_request(mdp5_kms->ctlm, crtc);
-               if (WARN_ON(!mdp5_crtc->ctl))
-                       return -EINVAL;
-       }
-
        /* verify that there are not too many planes attached to crtc
         * and that we don't have conflicting mixer stages:
         */
+       hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
        drm_atomic_crtc_state_for_each_plane(plane, state) {
                struct drm_plane_state *pstate;
-
-               if (cnt >= ARRAY_SIZE(pstates)) {
+               if (cnt >= (hw_cfg->lm.nb_stages)) {
                        dev_err(dev->dev, "too many planes!\n");
                        return -EINVAL;
                }
@@ -369,13 +403,13 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
                 */
                if (!pstate)
                        pstate = plane->state;
-
                pstates[cnt].plane = plane;
                pstates[cnt].state = to_mdp5_plane_state(pstate);
 
                cnt++;
        }
 
+       /* assign a stage based on sorted zpos property */
        sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
 
        for (i = 0; i < cnt; i++) {
@@ -388,13 +422,15 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
        return 0;
 }
 
-static void mdp5_crtc_atomic_begin(struct drm_crtc *crtc)
+static void mdp5_crtc_atomic_begin(struct drm_crtc *crtc,
+                                  struct drm_crtc_state *old_crtc_state)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        DBG("%s: begin", mdp5_crtc->name);
 }
 
-static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc)
+static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc,
+                                  struct drm_crtc_state *old_crtc_state)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct drm_device *dev = crtc->dev;
@@ -691,8 +727,8 @@ void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
        complete_flip(crtc, file);
 }
 
-/* set interface for routing crtc->encoder: */
-void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf)
+void mdp5_crtc_set_pipeline(struct drm_crtc *crtc,
+               struct mdp5_interface *intf, struct mdp5_ctl *ctl)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
@@ -715,7 +751,8 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf)
 
        mdp_irq_update(&mdp5_kms->base);
 
-       mdp5_ctl_set_intf(mdp5_crtc->ctl, intf);
+       mdp5_crtc->ctl = ctl;
+       mdp5_ctl_set_pipeline(ctl, intf, lm);
 }
 
 int mdp5_crtc_get_lm(struct drm_crtc *crtc)
@@ -724,12 +761,6 @@ int mdp5_crtc_get_lm(struct drm_crtc *crtc)
        return WARN_ON(!crtc) ? -EINVAL : 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;
-}
-
 void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
@@ -774,7 +805,5 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
        drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
        plane->crtc = crtc;
 
-       mdp5_plane_install_properties(plane, &crtc->base);
-
        return crtc;
 }
index f2530f224a762be72e92b32ed2c57521311f9603..4e81ca4f964afbb2ccecab23185227375a9f9069 100644 (file)
@@ -17,7 +17,7 @@
 /*
  * CTL - MDP Control Pool Manager
  *
- * Controls are shared between all CRTCs.
+ * Controls are shared between all display interfaces.
  *
  * They are intended to be used for data path configuration.
  * The top level register programming describes the complete data path for
  *
  * In certain use cases (high-resolution dual pipe), one single CTL can be
  * shared across multiple CRTCs.
- *
- * Because the number of CTLs can be less than the number of CRTCs,
- * CTLs are dynamically allocated from a pool of CTLs, only once a CRTC is
- * requested by the client (in mdp5_crtc_mode_set()).
  */
 
+#define CTL_STAT_BUSY          0x1
+#define CTL_STAT_BOOKED        0x2
+
 struct op_mode {
        struct mdp5_interface intf;
 
@@ -46,8 +45,8 @@ struct mdp5_ctl {
        u32 id;
        int lm;
 
-       /* whether this CTL has been allocated or not: */
-       bool busy;
+       /* CTL status bitmask */
+       u32 status;
 
        /* Operation Mode Configuration for the Pipeline */
        struct op_mode pipeline;
@@ -61,7 +60,10 @@ struct mdp5_ctl {
 
        bool cursor_on;
 
-       struct drm_crtc *crtc;
+       /* True if the current CTL has FLUSH bits pending for single FLUSH. */
+       bool flush_pending;
+
+       struct mdp5_ctl *pair; /* Paired CTL to be flushed together */
 };
 
 struct mdp5_ctl_manager {
@@ -74,6 +76,10 @@ struct mdp5_ctl_manager {
        /* to filter out non-present bits in the current hardware config */
        u32 flush_hw_mask;
 
+       /* status for single FLUSH */
+       bool single_flush_supported;
+       u32 single_flush_pending_mask;
+
        /* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */
        spinlock_t pool_lock;
        struct mdp5_ctl ctls[MAX_CTL];
@@ -168,11 +174,21 @@ static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
        spin_unlock_irqrestore(&ctl->hw_lock, flags);
 }
 
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
+int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl,
+               struct mdp5_interface *intf, int lm)
 {
        struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
        struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
 
+       if (unlikely(WARN_ON(intf->num != ctl->pipeline.intf.num))) {
+               dev_err(mdp5_kms->dev->dev,
+                       "CTL %d is allocated by INTF %d, but used by INTF %d\n",
+                       ctl->id, ctl->pipeline.intf.num, intf->num);
+               return -EINVAL;
+       }
+
+       ctl->lm = lm;
+
        memcpy(&ctl->pipeline.intf, intf, sizeof(*intf));
 
        ctl->pipeline.start_mask = mdp_ctl_flush_mask_lm(ctl->lm) |
@@ -287,29 +303,85 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable)
                blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
 
        ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
+       ctl->cursor_on = 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)
+static u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
+               enum mdp_mixer_stage_id stage)
+{
+       switch (pipe) {
+       case SSPP_VIG0: return MDP5_CTL_LAYER_REG_VIG0(stage);
+       case SSPP_VIG1: return MDP5_CTL_LAYER_REG_VIG1(stage);
+       case SSPP_VIG2: return MDP5_CTL_LAYER_REG_VIG2(stage);
+       case SSPP_RGB0: return MDP5_CTL_LAYER_REG_RGB0(stage);
+       case SSPP_RGB1: return MDP5_CTL_LAYER_REG_RGB1(stage);
+       case SSPP_RGB2: return MDP5_CTL_LAYER_REG_RGB2(stage);
+       case SSPP_DMA0: return MDP5_CTL_LAYER_REG_DMA0(stage);
+       case SSPP_DMA1: return MDP5_CTL_LAYER_REG_DMA1(stage);
+       case SSPP_VIG3: return MDP5_CTL_LAYER_REG_VIG3(stage);
+       case SSPP_RGB3: return MDP5_CTL_LAYER_REG_RGB3(stage);
+       default:        return 0;
+       }
+}
+
+static u32 mdp_ctl_blend_ext_mask(enum mdp5_pipe pipe,
+               enum mdp_mixer_stage_id stage)
+{
+       if (stage < STAGE6)
+               return 0;
+
+       switch (pipe) {
+       case SSPP_VIG0: return MDP5_CTL_LAYER_EXT_REG_VIG0_BIT3;
+       case SSPP_VIG1: return MDP5_CTL_LAYER_EXT_REG_VIG1_BIT3;
+       case SSPP_VIG2: return MDP5_CTL_LAYER_EXT_REG_VIG2_BIT3;
+       case SSPP_RGB0: return MDP5_CTL_LAYER_EXT_REG_RGB0_BIT3;
+       case SSPP_RGB1: return MDP5_CTL_LAYER_EXT_REG_RGB1_BIT3;
+       case SSPP_RGB2: return MDP5_CTL_LAYER_EXT_REG_RGB2_BIT3;
+       case SSPP_DMA0: return MDP5_CTL_LAYER_EXT_REG_DMA0_BIT3;
+       case SSPP_DMA1: return MDP5_CTL_LAYER_EXT_REG_DMA1_BIT3;
+       case SSPP_VIG3: return MDP5_CTL_LAYER_EXT_REG_VIG3_BIT3;
+       case SSPP_RGB3: return MDP5_CTL_LAYER_EXT_REG_RGB3_BIT3;
+       default:        return 0;
+       }
+}
+
+int mdp5_ctl_blend(struct mdp5_ctl *ctl, u8 *stage, u32 stage_cnt,
+       u32 ctl_blend_op_flags)
 {
        unsigned long flags;
+       u32 blend_cfg = 0, blend_ext_cfg = 0;
+       int i, start_stage;
+
+       if (ctl_blend_op_flags & MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT) {
+               start_stage = STAGE0;
+               blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
+       } else {
+               start_stage = STAGE_BASE;
+       }
 
+       for (i = start_stage; i < start_stage + stage_cnt; i++) {
+               blend_cfg |= mdp_ctl_blend_mask(stage[i], i);
+               blend_ext_cfg |= mdp_ctl_blend_ext_mask(stage[i], i);
+       }
+
+       spin_lock_irqsave(&ctl->hw_lock, flags);
        if (ctl->cursor_on)
                blend_cfg |=  MDP5_CTL_LAYER_REG_CURSOR_OUT;
-       else
-               blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
 
-       spin_lock_irqsave(&ctl->hw_lock, flags);
-       ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
+       ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, ctl->lm), blend_cfg);
+       ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, ctl->lm), blend_ext_cfg);
        spin_unlock_irqrestore(&ctl->hw_lock, flags);
 
-       ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(lm);
+       ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(ctl->lm);
+
+       DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x", ctl->lm,
+               blend_cfg, blend_ext_cfg);
 
        return 0;
 }
@@ -379,6 +451,31 @@ static u32 fix_sw_flush(struct mdp5_ctl *ctl, u32 flush_mask)
        return sw_mask;
 }
 
+static void fix_for_single_flush(struct mdp5_ctl *ctl, u32 *flush_mask,
+               u32 *flush_id)
+{
+       struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+
+       if (ctl->pair) {
+               DBG("CTL %d FLUSH pending mask %x", ctl->id, *flush_mask);
+               ctl->flush_pending = true;
+               ctl_mgr->single_flush_pending_mask |= (*flush_mask);
+               *flush_mask = 0;
+
+               if (ctl->pair->flush_pending) {
+                       *flush_id = min_t(u32, ctl->id, ctl->pair->id);
+                       *flush_mask = ctl_mgr->single_flush_pending_mask;
+
+                       ctl->flush_pending = false;
+                       ctl->pair->flush_pending = false;
+                       ctl_mgr->single_flush_pending_mask = 0;
+
+                       DBG("Single FLUSH mask %x,ID %d", *flush_mask,
+                               *flush_id);
+               }
+       }
+}
+
 /**
  * mdp5_ctl_commit() - Register Flush
  *
@@ -400,6 +497,8 @@ u32 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;
+       u32 flush_id = ctl->id;
+       u32 curr_ctl_flush_mask;
 
        pipeline->start_mask &= ~flush_mask;
 
@@ -415,9 +514,13 @@ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
 
        flush_mask &= ctl_mgr->flush_hw_mask;
 
+       curr_ctl_flush_mask = flush_mask;
+
+       fix_for_single_flush(ctl, &flush_mask, &flush_id);
+
        if (flush_mask) {
                spin_lock_irqsave(&ctl->hw_lock, flags);
-               ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask);
+               ctl_write(ctl, REG_MDP5_CTL_FLUSH(flush_id), flush_mask);
                spin_unlock_irqrestore(&ctl->hw_lock, flags);
        }
 
@@ -426,7 +529,7 @@ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
                refill_start_mask(ctl);
        }
 
-       return flush_mask;
+       return curr_ctl_flush_mask;
 }
 
 u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl)
@@ -434,59 +537,85 @@ u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl)
        return ctl_read(ctl, REG_MDP5_CTL_FLUSH(ctl->id));
 }
 
-void mdp5_ctl_release(struct mdp5_ctl *ctl)
+int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl)
 {
-       struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
-       unsigned long flags;
+       return WARN_ON(!ctl) ? -EINVAL : ctl->id;
+}
 
-       if (unlikely(WARN_ON(ctl->id >= MAX_CTL) || !ctl->busy)) {
-               dev_err(ctl_mgr->dev->dev, "CTL %d in bad state (%d)",
-                               ctl->id, ctl->busy);
-               return;
+/*
+ * mdp5_ctl_pair() - Associate 2 booked CTLs for single FLUSH
+ */
+int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable)
+{
+       struct mdp5_ctl_manager *ctl_mgr = ctlx->ctlm;
+       struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
+
+       /* do nothing silently if hw doesn't support */
+       if (!ctl_mgr->single_flush_supported)
+               return 0;
+
+       if (!enable) {
+               ctlx->pair = NULL;
+               ctly->pair = NULL;
+               mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0), 0);
+               return 0;
+       } else if ((ctlx->pair != NULL) || (ctly->pair != NULL)) {
+               dev_err(ctl_mgr->dev->dev, "CTLs already paired\n");
+               return -EINVAL;
+       } else if (!(ctlx->status & ctly->status & CTL_STAT_BOOKED)) {
+               dev_err(ctl_mgr->dev->dev, "Only pair booked CTLs\n");
+               return -EINVAL;
        }
 
-       spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
-       ctl->busy = false;
-       spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
+       ctlx->pair = ctly;
+       ctly->pair = ctlx;
 
-       DBG("CTL %d released", ctl->id);
-}
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0),
+               MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN);
 
-int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl)
-{
-       return WARN_ON(!ctl) ? -EINVAL : ctl->id;
+       return 0;
 }
 
 /*
- * mdp5_ctl_request() - CTL dynamic allocation
+ * mdp5_ctl_request() - CTL allocation
  *
- * Note: Current implementation considers that we can only have one CRTC per CTL
+ * Try to return booked CTL for @intf_num is 1 or 2, unbooked for other INTFs.
+ * If no CTL is available in preferred category, allocate from the other one.
  *
- * @return first free CTL
+ * @return fail if no CTL is available.
  */
 struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr,
-               struct drm_crtc *crtc)
+               int intf_num)
 {
        struct mdp5_ctl *ctl = NULL;
+       const u32 checkm = CTL_STAT_BUSY | CTL_STAT_BOOKED;
+       u32 match = ((intf_num == 1) || (intf_num == 2)) ? CTL_STAT_BOOKED : 0;
        unsigned long flags;
        int c;
 
        spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
 
+       /* search the preferred */
        for (c = 0; c < ctl_mgr->nctl; c++)
-               if (!ctl_mgr->ctls[c].busy)
-                       break;
+               if ((ctl_mgr->ctls[c].status & checkm) == match)
+                       goto found;
 
-       if (unlikely(c >= ctl_mgr->nctl)) {
-               dev_err(ctl_mgr->dev->dev, "No more CTL available!");
-               goto unlock;
-       }
+       dev_warn(ctl_mgr->dev->dev,
+               "fall back to the other CTL category for INTF %d!\n", intf_num);
 
-       ctl = &ctl_mgr->ctls[c];
+       match ^= CTL_STAT_BOOKED;
+       for (c = 0; c < ctl_mgr->nctl; c++)
+               if ((ctl_mgr->ctls[c].status & checkm) == match)
+                       goto found;
 
-       ctl->lm = mdp5_crtc_get_lm(crtc);
-       ctl->crtc = crtc;
-       ctl->busy = true;
+       dev_err(ctl_mgr->dev->dev, "No more CTL available!");
+       goto unlock;
+
+found:
+       ctl = &ctl_mgr->ctls[c];
+       ctl->pipeline.intf.num = intf_num;
+       ctl->lm = -1;
+       ctl->status |= CTL_STAT_BUSY;
        ctl->pending_ctl_trigger = 0;
        DBG("CTL %d allocated", ctl->id);
 
@@ -515,9 +644,11 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctl_mgr)
 }
 
 struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
-               void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg)
+               void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd)
 {
        struct mdp5_ctl_manager *ctl_mgr;
+       const struct mdp5_cfg_hw *hw_cfg = mdp5_cfg_get_hw_config(cfg_hnd);
+       int rev = mdp5_cfg_get_hw_rev(cfg_hnd);
        const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl;
        unsigned long flags;
        int c, ret;
@@ -551,14 +682,28 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
                if (WARN_ON(!ctl_cfg->base[c])) {
                        dev_err(dev->dev, "CTL_%d: base is null!\n", c);
                        ret = -EINVAL;
+                       spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
                        goto fail;
                }
                ctl->ctlm = ctl_mgr;
                ctl->id = c;
                ctl->reg_offset = ctl_cfg->base[c];
-               ctl->busy = false;
+               ctl->status = 0;
                spin_lock_init(&ctl->hw_lock);
        }
+
+       /*
+        * In Dual DSI case, CTL0 and CTL1 are always assigned to two DSI
+        * interfaces to support single FLUSH feature (Flush CTL0 and CTL1 when
+        * only write into CTL0's FLUSH register) to keep two DSI pipes in sync.
+        * Single FLUSH is supported from hw rev v3.0.
+        */
+       if (rev >= 3) {
+               ctl_mgr->single_flush_supported = true;
+               /* Reserve CTL0/1 for INTF1/2 */
+               ctl_mgr->ctls[0].status |= CTL_STAT_BOOKED;
+               ctl_mgr->ctls[1].status |= CTL_STAT_BOOKED;
+       }
        spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
        DBG("Pool of %d CTLs created.", ctl_mgr->nctl);
 
index 4678228c4f14efb41f8d123230ffda3b0eb2917e..96148c6f863c8fe9e45d862eaa068fac0bb0dd0a 100644 (file)
@@ -23,7 +23,7 @@
  */
 struct mdp5_ctl_manager;
 struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
-               void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg);
+               void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd);
 void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctlm);
 void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
 
@@ -32,49 +32,32 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
  * mdp5_ctl_request(ctlm, ...) returns a ctl (CTL resource) handler,
  * 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);
+struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, int intf_num);
+
 int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl);
 
 struct mdp5_interface;
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf);
+int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_interface *intf,
+                               int lm);
 int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled);
 
 int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable);
-
-/*
- * blend_cfg (LM blender config):
- *
- * The function below allows the caller of mdp5_ctl_blend() to specify how pipes
- * are being blended according to their stage (z-order), through @blend_cfg arg.
- */
-static inline u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
-               enum mdp_mixer_stage_id stage)
-{
-       switch (pipe) {
-       case SSPP_VIG0: return MDP5_CTL_LAYER_REG_VIG0(stage);
-       case SSPP_VIG1: return MDP5_CTL_LAYER_REG_VIG1(stage);
-       case SSPP_VIG2: return MDP5_CTL_LAYER_REG_VIG2(stage);
-       case SSPP_RGB0: return MDP5_CTL_LAYER_REG_RGB0(stage);
-       case SSPP_RGB1: return MDP5_CTL_LAYER_REG_RGB1(stage);
-       case SSPP_RGB2: return MDP5_CTL_LAYER_REG_RGB2(stage);
-       case SSPP_DMA0: return MDP5_CTL_LAYER_REG_DMA0(stage);
-       case SSPP_DMA1: return MDP5_CTL_LAYER_REG_DMA1(stage);
-       case SSPP_VIG3: return MDP5_CTL_LAYER_REG_VIG3(stage);
-       case SSPP_RGB3: return MDP5_CTL_LAYER_REG_RGB3(stage);
-       default:        return 0;
-       }
-}
+int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable);
 
 /*
  * mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM)
  *
- * @blend_cfg: see LM blender config definition below
+ * @stage: array to contain the pipe num for each stage
+ * @stage_cnt: valid stage number in stage array
+ * @ctl_blend_op_flags: blender operation mode flags
  *
  * 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_BLEND_OP_FLAG_BORDER_OUT      BIT(0)
+int mdp5_ctl_blend(struct mdp5_ctl *ctl, u8 *stage, u32 stage_cnt,
+       u32 ctl_blend_op_flags);
 
 /**
  * mdp_ctl_flush_mask...() - Register FLUSH masks
@@ -91,8 +74,6 @@ u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf);
 u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask);
 u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl);
 
-void mdp5_ctl_release(struct mdp5_ctl *ctl);
-
 
 
 #endif /* __MDP5_CTL_H__ */
index de97c08f3f1fba04950749215e58f9f5a4dfe8f5..c9e32b08a7a0b3c8807ce76b78018630d315632c 100644 (file)
@@ -27,6 +27,8 @@ struct mdp5_encoder {
        spinlock_t intf_lock;   /* protect REG_MDP5_INTF_* registers */
        bool enabled;
        uint32_t bsc;
+
+       struct mdp5_ctl *ctl;
 };
 #define to_mdp5_encoder(x) container_of(x, struct mdp5_encoder, base)
 
@@ -222,14 +224,15 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
 
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
 
-       mdp5_crtc_set_intf(encoder->crtc, &mdp5_encoder->intf);
+       mdp5_crtc_set_pipeline(encoder->crtc, &mdp5_encoder->intf,
+                               mdp5_encoder->ctl);
 }
 
 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);
-       struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
+       struct mdp5_ctl *ctl = mdp5_encoder->ctl;
        int lm = mdp5_crtc_get_lm(encoder->crtc);
        struct mdp5_interface *intf = &mdp5_encoder->intf;
        int intfn = mdp5_encoder->intf.num;
@@ -264,7 +267,7 @@ 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);
-       struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
+       struct mdp5_ctl *ctl = mdp5_encoder->ctl;
        struct mdp5_interface *intf = &mdp5_encoder->intf;
        int intfn = mdp5_encoder->intf.num;
        unsigned long flags;
@@ -294,6 +297,7 @@ 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_encoder *mdp5_slave_enc = to_mdp5_encoder(slave_encoder);
        struct mdp5_kms *mdp5_kms;
        int intf_num;
        u32 data = 0;
@@ -316,12 +320,13 @@ int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
 
        /* 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_MDP_SPLIT_DPL_UPPER(0), 0);
        mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_LOWER(0), data);
        mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_EN(0), 1);
+
+       mdp5_ctl_pair(mdp5_encoder->ctl, mdp5_slave_enc->ctl, true);
+
        mdp5_disable(mdp5_kms);
 
        return 0;
@@ -329,7 +334,7 @@ int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
 
 /* initialize encoder */
 struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
-                               struct mdp5_interface *intf)
+                       struct mdp5_interface *intf, struct mdp5_ctl *ctl)
 {
        struct drm_encoder *encoder = NULL;
        struct mdp5_encoder *mdp5_encoder;
@@ -345,6 +350,7 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
 
        memcpy(&mdp5_encoder->intf, intf, sizeof(mdp5_encoder->intf));
        encoder = &mdp5_encoder->base;
+       mdp5_encoder->ctl = ctl;
 
        spin_lock_init(&mdp5_encoder->intf_lock);
 
index 33bd4c6160dd0ded0fce6f676e02ee803c2572c7..b1f73bee13682a29e1bc68a84f991e55fa170723 100644 (file)
 #include "msm_drv.h"
 #include "mdp5_kms.h"
 
-void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask)
+void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
+               uint32_t old_irqmask)
 {
+       mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_MDP_INTR_CLEAR(0),
+               irqmask ^ (irqmask & old_irqmask));
        mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_MDP_INTR_EN(0), irqmask);
 }
 
@@ -71,9 +74,10 @@ static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)
        struct drm_device *dev = mdp5_kms->dev;
        struct msm_drm_private *priv = dev->dev_private;
        unsigned int id;
-       uint32_t status;
+       uint32_t status, enable;
 
-       status = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_STATUS(0));
+       enable = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_EN(0));
+       status = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_STATUS(0)) & enable;
        mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), status);
 
        VERB("status=%08x", status);
@@ -112,15 +116,24 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
 
 int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
 {
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+
+       mdp5_enable(mdp5_kms);
        mdp_update_vblank_mask(to_mdp_kms(kms),
                        mdp5_crtc_vblank(crtc), true);
+       mdp5_disable(mdp5_kms);
+
        return 0;
 }
 
 void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
 {
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+
+       mdp5_enable(mdp5_kms);
        mdp_update_vblank_mask(to_mdp_kms(kms),
                        mdp5_crtc_vblank(crtc), false);
+       mdp5_disable(mdp5_kms);
 }
 
 /*
index 206f758f7d64849af986e6c70589bf96d7b0cb7b..047cb0433ccbe5156c5ebd2734b66586e75c7e27 100644 (file)
@@ -76,7 +76,20 @@ static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *st
 
 static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
 {
+       int i;
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       int nplanes = mdp5_kms->dev->mode_config.num_total_plane;
+
+       for (i = 0; i < nplanes; i++) {
+               struct drm_plane *plane = state->planes[i];
+               struct drm_plane_state *plane_state = state->plane_states[i];
+
+               if (!plane)
+                       continue;
+
+               mdp5_plane_complete_commit(plane, plane_state);
+       }
+
        mdp5_disable(mdp5_kms);
 }
 
@@ -164,7 +177,8 @@ int mdp5_disable(struct mdp5_kms *mdp5_kms)
        clk_disable_unprepare(mdp5_kms->ahb_clk);
        clk_disable_unprepare(mdp5_kms->axi_clk);
        clk_disable_unprepare(mdp5_kms->core_clk);
-       clk_disable_unprepare(mdp5_kms->lut_clk);
+       if (mdp5_kms->lut_clk)
+               clk_disable_unprepare(mdp5_kms->lut_clk);
 
        return 0;
 }
@@ -176,14 +190,15 @@ int mdp5_enable(struct mdp5_kms *mdp5_kms)
        clk_prepare_enable(mdp5_kms->ahb_clk);
        clk_prepare_enable(mdp5_kms->axi_clk);
        clk_prepare_enable(mdp5_kms->core_clk);
-       clk_prepare_enable(mdp5_kms->lut_clk);
+       if (mdp5_kms->lut_clk)
+               clk_prepare_enable(mdp5_kms->lut_clk);
 
        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)
+               enum mdp5_intf_mode intf_mode, struct mdp5_ctl *ctl)
 {
        struct drm_device *dev = mdp5_kms->dev;
        struct msm_drm_private *priv = dev->dev_private;
@@ -196,9 +211,9 @@ static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
 
        if ((intf_type == INTF_DSI) &&
                (intf_mode == MDP5_INTF_DSI_MODE_COMMAND))
-               encoder = mdp5_cmd_encoder_init(dev, &intf);
+               encoder = mdp5_cmd_encoder_init(dev, &intf, ctl);
        else
-               encoder = mdp5_encoder_init(dev, &intf);
+               encoder = mdp5_encoder_init(dev, &intf, ctl);
 
        if (IS_ERR(encoder)) {
                dev_err(dev->dev, "failed to construct encoder\n");
@@ -236,6 +251,8 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
        const struct mdp5_cfg_hw *hw_cfg =
                                        mdp5_cfg_get_hw_config(mdp5_kms->cfg);
        enum mdp5_intf_type intf_type = hw_cfg->intf.connect[intf_num];
+       struct mdp5_ctl_manager *ctlm = mdp5_kms->ctlm;
+       struct mdp5_ctl *ctl;
        struct drm_encoder *encoder;
        int ret = 0;
 
@@ -246,8 +263,14 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
                if (!priv->edp)
                        break;
 
+               ctl = mdp5_ctlm_request(ctlm, intf_num);
+               if (!ctl) {
+                       ret = -EINVAL;
+                       break;
+               }
+
                encoder = construct_encoder(mdp5_kms, INTF_eDP, intf_num,
-                                       MDP5_INTF_MODE_NONE);
+                                       MDP5_INTF_MODE_NONE, ctl);
                if (IS_ERR(encoder)) {
                        ret = PTR_ERR(encoder);
                        break;
@@ -259,8 +282,14 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
                if (!priv->hdmi)
                        break;
 
+               ctl = mdp5_ctlm_request(ctlm, intf_num);
+               if (!ctl) {
+                       ret = -EINVAL;
+                       break;
+               }
+
                encoder = construct_encoder(mdp5_kms, INTF_HDMI, intf_num,
-                                       MDP5_INTF_MODE_NONE);
+                                       MDP5_INTF_MODE_NONE, ctl);
                if (IS_ERR(encoder)) {
                        ret = PTR_ERR(encoder);
                        break;
@@ -285,14 +314,20 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
                if (!priv->dsi[dsi_id])
                        break;
 
+               ctl = mdp5_ctlm_request(ctlm, intf_num);
+               if (!ctl) {
+                       ret = -EINVAL;
+                       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);
+                                                       intf_num, mode, ctl);
+                       if (IS_ERR(dsi_encs[i])) {
+                               ret = PTR_ERR(dsi_encs[i]);
                                break;
                        }
                }
@@ -314,9 +349,12 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
        static const enum mdp5_pipe crtcs[] = {
                        SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
        };
-       static const enum mdp5_pipe pub_planes[] = {
+       static const enum mdp5_pipe vig_planes[] = {
                        SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
        };
+       static const enum mdp5_pipe dma_planes[] = {
+                       SSPP_DMA0, SSPP_DMA1,
+       };
        struct drm_device *dev = mdp5_kms->dev;
        struct msm_drm_private *priv = dev->dev_private;
        const struct mdp5_cfg_hw *hw_cfg;
@@ -337,7 +375,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
                struct drm_crtc *crtc;
 
                plane = mdp5_plane_init(dev, crtcs[i], true,
-                               hw_cfg->pipe_rgb.base[i]);
+                       hw_cfg->pipe_rgb.base[i], hw_cfg->pipe_rgb.caps);
                if (IS_ERR(plane)) {
                        ret = PTR_ERR(plane);
                        dev_err(dev->dev, "failed to construct plane for %s (%d)\n",
@@ -355,16 +393,30 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
                priv->crtcs[priv->num_crtcs++] = crtc;
        }
 
-       /* Construct public planes: */
+       /* Construct video planes: */
        for (i = 0; i < hw_cfg->pipe_vig.count; i++) {
                struct drm_plane *plane;
 
-               plane = mdp5_plane_init(dev, pub_planes[i], false,
-                               hw_cfg->pipe_vig.base[i]);
+               plane = mdp5_plane_init(dev, vig_planes[i], false,
+                       hw_cfg->pipe_vig.base[i], hw_cfg->pipe_vig.caps);
                if (IS_ERR(plane)) {
                        ret = PTR_ERR(plane);
                        dev_err(dev->dev, "failed to construct %s plane: %d\n",
-                                       pipe2name(pub_planes[i]), ret);
+                                       pipe2name(vig_planes[i]), ret);
+                       goto fail;
+               }
+       }
+
+       /* DMA planes */
+       for (i = 0; i < hw_cfg->pipe_dma.count; i++) {
+               struct drm_plane *plane;
+
+               plane = mdp5_plane_init(dev, dma_planes[i], false,
+                               hw_cfg->pipe_dma.base[i], hw_cfg->pipe_dma.caps);
+               if (IS_ERR(plane)) {
+                       ret = PTR_ERR(plane);
+                       dev_err(dev->dev, "failed to construct %s plane: %d\n",
+                                       pipe2name(dma_planes[i]), ret);
                        goto fail;
                }
        }
@@ -476,7 +528,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
                goto fail;
        ret = get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk");
        if (ret)
-               goto fail;
+               DBG("failed to get (optional) lut_clk clock");
        ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk");
        if (ret)
                goto fail;
@@ -508,7 +560,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
                goto fail;
        }
 
-       mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, config->hw);
+       mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg);
        if (IS_ERR(mdp5_kms->ctlm)) {
                ret = PTR_ERR(mdp5_kms->ctlm);
                mdp5_kms->ctlm = NULL;
@@ -564,6 +616,11 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
                goto fail;
        }
 
+       dev->mode_config.min_width = 0;
+       dev->mode_config.min_height = 0;
+       dev->mode_config.max_width = config->hw->lm.max_width;
+       dev->mode_config.max_height = config->hw->lm.max_height;
+
        return kms;
 
 fail:
index e0eb24587c84d7887a69c47c0428ad3f0d4f1396..0bb62423586e2e2126efa6acfe618ed41b90d982 100644 (file)
@@ -70,18 +70,12 @@ struct mdp5_kms {
 struct mdp5_plane_state {
        struct drm_plane_state base;
 
-       /* "virtual" zpos.. we calculate actual mixer-stage at runtime
-        * by sorting the attached planes by zpos and then assigning
-        * mixer stage lowest to highest.  Private planes get default
-        * zpos of zero, and public planes a unique value that is
-        * greater than zero.  This way, things work out if a naive
-        * userspace assigns planes to a crtc without setting zpos.
-        */
-       int zpos;
+       /* aligned with property */
+       uint8_t premultiplied;
+       uint8_t zpos;
+       uint8_t alpha;
 
-       /* the actual mixer stage, calculated in crtc->atomic_check()
-        * NOTE: this should move to mdp5_crtc_state, when that exists
-        */
+       /* assigned by crtc blender */
        enum mdp_mixer_stage_id stage;
 
        /* some additional transactional status to help us know in the
@@ -192,7 +186,8 @@ static inline uint32_t lm2ppdone(int lm)
 int mdp5_disable(struct mdp5_kms *mdp5_kms);
 int mdp5_enable(struct mdp5_kms *mdp5_kms);
 
-void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask);
+void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
+               uint32_t old_irqmask);
 void mdp5_irq_preinstall(struct msm_kms *kms);
 int mdp5_irq_postinstall(struct msm_kms *kms);
 void mdp5_irq_uninstall(struct msm_kms *kms);
@@ -202,58 +197,38 @@ void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms);
 void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms);
 
-static inline bool pipe_supports_yuv(enum mdp5_pipe pipe)
-{
-       switch (pipe) {
-       case SSPP_VIG0:
-       case SSPP_VIG1:
-       case SSPP_VIG2:
-       case SSPP_VIG3:
-               return true;
-       default:
-               return false;
-       }
-}
-
-static inline
-uint32_t mdp5_get_formats(enum mdp5_pipe pipe, uint32_t *pixel_formats,
-               uint32_t max_formats)
-{
-       return mdp_get_formats(pixel_formats, max_formats,
-                               !pipe_supports_yuv(pipe));
-}
-
-void mdp5_plane_install_properties(struct drm_plane *plane,
-               struct drm_mode_object *obj);
 uint32_t mdp5_plane_get_flush(struct drm_plane *plane);
 void mdp5_plane_complete_flip(struct drm_plane *plane);
+void mdp5_plane_complete_commit(struct drm_plane *plane,
+       struct drm_plane_state *state);
 enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
 struct drm_plane *mdp5_plane_init(struct drm_device *dev,
-               enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset);
+               enum mdp5_pipe pipe, bool private_plane,
+               uint32_t reg_offset, uint32_t caps);
 
 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, struct mdp5_interface *intf);
+void mdp5_crtc_set_pipeline(struct drm_crtc *crtc,
+               struct mdp5_interface *intf, struct mdp5_ctl *ctl);
 void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc);
 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,
-               struct mdp5_interface *intf);
+               struct mdp5_interface *intf, struct mdp5_ctl *ctl);
 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);
+               struct mdp5_interface *intf, struct mdp5_ctl *ctl);
 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)
+static inline struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
+               struct mdp5_interface *intf, struct mdp5_ctl *ctl)
 {
        return ERR_PTR(-EINVAL);
 }
index 57b8f56ae9d06fb458266181a8344858e381e6b5..07fb62fea6dc1d142928a2838134ca30c88fdfac 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.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -26,13 +26,12 @@ struct mdp5_plane {
 
        spinlock_t pipe_lock;   /* protect REG_MDP5_PIPE_* registers */
        uint32_t reg_offset;
+       uint32_t caps;
 
        uint32_t flush_mask;    /* used to commit pipe registers */
 
        uint32_t nformats;
        uint32_t formats[32];
-
-       bool enabled;
 };
 #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
 
@@ -42,6 +41,7 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
                unsigned int crtc_w, unsigned int crtc_h,
                uint32_t src_x, uint32_t src_y,
                uint32_t src_w, uint32_t src_h);
+
 static void set_scanout_locked(struct drm_plane *plane,
                struct drm_framebuffer *fb);
 
@@ -56,44 +56,132 @@ static bool plane_enabled(struct drm_plane_state *state)
        return state->fb && state->crtc;
 }
 
-static int mdp5_plane_disable(struct drm_plane *plane)
+static void mdp5_plane_destroy(struct drm_plane *plane)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
-       struct mdp5_kms *mdp5_kms = get_kms(plane);
-       enum mdp5_pipe pipe = mdp5_plane->pipe;
 
-       DBG("%s: disable", mdp5_plane->name);
-
-       if (mdp5_kms) {
-               /* Release the memory we requested earlier from the SMP: */
-               mdp5_smp_release(mdp5_kms->smp, pipe);
-       }
+       drm_plane_helper_disable(plane);
+       drm_plane_cleanup(plane);
 
-       return 0;
+       kfree(mdp5_plane);
 }
 
-static void mdp5_plane_destroy(struct drm_plane *plane)
+static void mdp5_plane_install_rotation_property(struct drm_device *dev,
+               struct drm_plane *plane)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
 
-       drm_plane_helper_disable(plane);
-       drm_plane_cleanup(plane);
+       if (!(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP) &&
+               !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP))
+               return;
 
-       kfree(mdp5_plane);
+       if (!dev->mode_config.rotation_property)
+               dev->mode_config.rotation_property =
+                       drm_mode_create_rotation_property(dev,
+                       BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y));
+
+       if (dev->mode_config.rotation_property)
+               drm_object_attach_property(&plane->base,
+                       dev->mode_config.rotation_property,
+                       0);
 }
 
 /* helper to install properties which are common to planes and crtcs */
-void mdp5_plane_install_properties(struct drm_plane *plane,
+static void mdp5_plane_install_properties(struct drm_plane *plane,
                struct drm_mode_object *obj)
 {
-       // XXX
+       struct drm_device *dev = plane->dev;
+       struct msm_drm_private *dev_priv = dev->dev_private;
+       struct drm_property *prop;
+
+#define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \
+               prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \
+               if (!prop) { \
+                       prop = drm_property_##fnc(dev, 0, #name, \
+                               ##__VA_ARGS__); \
+                       if (!prop) { \
+                               dev_warn(dev->dev, \
+                                       "Create property %s failed\n", \
+                                       #name); \
+                               return; \
+                       } \
+                       dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \
+               } \
+               drm_object_attach_property(&plane->base, prop, init_val); \
+       } while (0)
+
+#define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
+               INSTALL_PROPERTY(name, NAME, init_val, \
+                               create_range, min, max)
+
+#define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
+               INSTALL_PROPERTY(name, NAME, init_val, \
+                               create_enum, name##_prop_enum_list, \
+                               ARRAY_SIZE(name##_prop_enum_list))
+
+       INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1);
+
+       mdp5_plane_install_rotation_property(dev, plane);
+
+#undef INSTALL_RANGE_PROPERTY
+#undef INSTALL_ENUM_PROPERTY
+#undef INSTALL_PROPERTY
+}
+
+static int mdp5_plane_atomic_set_property(struct drm_plane *plane,
+               struct drm_plane_state *state, struct drm_property *property,
+               uint64_t val)
+{
+       struct drm_device *dev = plane->dev;
+       struct mdp5_plane_state *pstate;
+       struct msm_drm_private *dev_priv = dev->dev_private;
+       int ret = 0;
+
+       pstate = to_mdp5_plane_state(state);
+
+#define SET_PROPERTY(name, NAME, type) do { \
+               if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
+                       pstate->name = (type)val; \
+                       DBG("Set property %s %d", #name, (type)val); \
+                       goto done; \
+               } \
+       } while (0)
+
+       SET_PROPERTY(zpos, ZPOS, uint8_t);
+
+       dev_err(dev->dev, "Invalid property\n");
+       ret = -EINVAL;
+done:
+       return ret;
+#undef SET_PROPERTY
 }
 
-int mdp5_plane_set_property(struct drm_plane *plane,
-               struct drm_property *property, uint64_t val)
+static int mdp5_plane_atomic_get_property(struct drm_plane *plane,
+               const struct drm_plane_state *state,
+               struct drm_property *property, uint64_t *val)
 {
-       // XXX
-       return -EINVAL;
+       struct drm_device *dev = plane->dev;
+       struct mdp5_plane_state *pstate;
+       struct msm_drm_private *dev_priv = dev->dev_private;
+       int ret = 0;
+
+       pstate = to_mdp5_plane_state(state);
+
+#define GET_PROPERTY(name, NAME, type) do { \
+               if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
+                       *val = pstate->name; \
+                       DBG("Get property %s %lld", #name, *val); \
+                       goto done; \
+               } \
+       } while (0)
+
+       GET_PROPERTY(zpos, ZPOS, uint8_t);
+
+       dev_err(dev->dev, "Invalid property\n");
+       ret = -EINVAL;
+done:
+       return ret;
+#undef SET_PROPERTY
 }
 
 static void mdp5_plane_reset(struct drm_plane *plane)
@@ -106,11 +194,15 @@ static void mdp5_plane_reset(struct drm_plane *plane)
        kfree(to_mdp5_plane_state(plane->state));
        mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
 
-       if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
-               mdp5_state->zpos = 0;
-       } else {
-               mdp5_state->zpos = 1 + drm_plane_index(plane);
-       }
+       /* assign default blend parameters */
+       mdp5_state->alpha = 255;
+       mdp5_state->premultiplied = 0;
+
+       if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+               mdp5_state->zpos = STAGE_BASE;
+       else
+               mdp5_state->zpos = STAGE0 + drm_plane_index(plane);
+
        mdp5_state->base.plane = plane;
 
        plane->state = &mdp5_state->base;
@@ -149,7 +241,9 @@ static const struct drm_plane_funcs mdp5_plane_funcs = {
                .update_plane = drm_atomic_helper_update_plane,
                .disable_plane = drm_atomic_helper_disable_plane,
                .destroy = mdp5_plane_destroy,
-               .set_property = mdp5_plane_set_property,
+               .set_property = drm_atomic_helper_plane_set_property,
+               .atomic_set_property = mdp5_plane_atomic_set_property,
+               .atomic_get_property = mdp5_plane_atomic_get_property,
                .reset = mdp5_plane_reset,
                .atomic_duplicate_state = mdp5_plane_duplicate_state,
                .atomic_destroy_state = mdp5_plane_destroy_state,
@@ -182,10 +276,44 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
        struct drm_plane_state *old_state = plane->state;
+       const struct mdp_format *format;
+       bool vflip, hflip;
 
        DBG("%s: check (%d -> %d)", mdp5_plane->name,
                        plane_enabled(old_state), plane_enabled(state));
 
+       if (plane_enabled(state)) {
+               format = to_mdp_format(msm_framebuffer_format(state->fb));
+               if (MDP_FORMAT_IS_YUV(format) &&
+                       !pipe_supports_yuv(mdp5_plane->caps)) {
+                       dev_err(plane->dev->dev,
+                               "Pipe doesn't support YUV\n");
+
+                       return -EINVAL;
+               }
+
+               if (!(mdp5_plane->caps & MDP_PIPE_CAP_SCALE) &&
+                       (((state->src_w >> 16) != state->crtc_w) ||
+                       ((state->src_h >> 16) != state->crtc_h))) {
+                       dev_err(plane->dev->dev,
+                               "Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
+                               state->src_w >> 16, state->src_h >> 16,
+                               state->crtc_w, state->crtc_h);
+
+                       return -EINVAL;
+               }
+
+               hflip = !!(state->rotation & BIT(DRM_REFLECT_X));
+               vflip = !!(state->rotation & BIT(DRM_REFLECT_Y));
+               if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) ||
+                       (hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) {
+                       dev_err(plane->dev->dev,
+                               "Pipe doesn't support flip\n");
+
+                       return -EINVAL;
+               }
+       }
+
        if (plane_enabled(state) && plane_enabled(old_state)) {
                /* we cannot change SMP block configuration during scanout: */
                bool full_modeset = false;
@@ -224,7 +352,6 @@ static void mdp5_plane_atomic_update(struct drm_plane *plane,
 
        if (!plane_enabled(state)) {
                to_mdp5_plane_state(state)->pending = true;
-               mdp5_plane_disable(plane);
        } else if (to_mdp5_plane_state(state)->mode_changed) {
                int ret;
                to_mdp5_plane_state(state)->pending = true;
@@ -365,16 +492,21 @@ static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
        return 0;
 }
 
-static int calc_scalex_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
+static int calc_scalex_steps(struct drm_plane *plane,
+               uint32_t pixel_format, uint32_t src, uint32_t dest,
                uint32_t phasex_steps[2])
 {
+       struct mdp5_kms *mdp5_kms = get_kms(plane);
+       struct device *dev = mdp5_kms->dev->dev;
        uint32_t phasex_step;
        unsigned int hsub;
        int ret;
 
        ret = calc_phase_step(src, dest, &phasex_step);
-       if (ret)
+       if (ret) {
+               dev_err(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret);
                return ret;
+       }
 
        hsub = drm_format_horz_chroma_subsampling(pixel_format);
 
@@ -384,16 +516,21 @@ static int calc_scalex_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
        return 0;
 }
 
-static int calc_scaley_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
+static int calc_scaley_steps(struct drm_plane *plane,
+               uint32_t pixel_format, uint32_t src, uint32_t dest,
                uint32_t phasey_steps[2])
 {
+       struct mdp5_kms *mdp5_kms = get_kms(plane);
+       struct device *dev = mdp5_kms->dev->dev;
        uint32_t phasey_step;
        unsigned int vsub;
        int ret;
 
        ret = calc_phase_step(src, dest, &phasey_step);
-       if (ret)
+       if (ret) {
+               dev_err(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret);
                return ret;
+       }
 
        vsub = drm_format_vert_chroma_subsampling(pixel_format);
 
@@ -403,28 +540,38 @@ static int calc_scaley_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
        return 0;
 }
 
-static uint32_t get_scalex_config(uint32_t src, uint32_t dest)
-{
-       uint32_t filter;
-
-       filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
-
-       return  MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
-               MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(filter) |
-               MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(filter)  |
-               MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(filter);
-}
-
-static uint32_t get_scaley_config(uint32_t src, uint32_t dest)
+static uint32_t get_scale_config(enum mdp_chroma_samp_type chroma_sample,
+               uint32_t src, uint32_t dest, bool hor)
 {
-       uint32_t filter;
-
-       filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
+       uint32_t y_filter =   (src <= dest) ? SCALE_FILTER_CA  : SCALE_FILTER_PCMN;
+       uint32_t y_a_filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
+       uint32_t uv_filter = ((src / 2) <= dest) ? /* 2x upsample */
+                       SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
+       uint32_t value = 0;
+
+       if (chroma_sample == CHROMA_420 || chroma_sample == CHROMA_H2V1) {
+               if (hor)
+                       value = MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
+                               MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(y_filter) |
+                               MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(y_a_filter) |
+                               MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter);
+               else
+                       value = MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
+                               MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(y_filter) |
+                               MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(y_a_filter) |
+                               MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter);
+       } else if (src != dest) {
+               if (hor)
+                       value = MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
+                               MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(y_a_filter) |
+                               MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(y_a_filter);
+               else
+                       value = MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
+                               MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(y_a_filter) |
+                               MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(y_a_filter);
+       }
 
-       return  MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
-               MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(filter) |
-               MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(filter)  |
-               MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(filter);
+       return value;
 }
 
 static int mdp5_plane_mode_set(struct drm_plane *plane,
@@ -435,8 +582,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
                uint32_t src_w, uint32_t src_h)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       struct drm_plane_state *pstate = plane->state;
        struct mdp5_kms *mdp5_kms = get_kms(plane);
-       struct device *dev = mdp5_kms->dev->dev;
        enum mdp5_pipe pipe = mdp5_plane->pipe;
        const struct mdp_format *format;
        uint32_t nplanes, config = 0;
@@ -444,6 +591,7 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
        uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,};
        uint32_t hdecm = 0, vdecm = 0;
        uint32_t pix_format;
+       bool vflip, hflip;
        unsigned long flags;
        int ret;
 
@@ -468,7 +616,7 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
 
        /* Request some memory from the SMP: */
        ret = mdp5_smp_request(mdp5_kms->smp,
-                       mdp5_plane->pipe, fb->pixel_format, src_w);
+                       mdp5_plane->pipe, format, src_w, false);
        if (ret)
                return ret;
 
@@ -480,29 +628,23 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
         */
        mdp5_smp_configure(mdp5_kms->smp, pipe);
 
-       /* SCALE is used to both scale and up-sample chroma components */
+       ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, phasex_step);
+       if (ret)
+               return ret;
 
-       if ((src_w != crtc_w) || MDP_FORMAT_IS_YUV(format)) {
-               /* TODO calc hdecm */
-               ret = calc_scalex_steps(pix_format, src_w, crtc_w, phasex_step);
-               if (ret) {
-                       dev_err(dev, "X scaling (%d -> %d) failed: %d\n",
-                                       src_w, crtc_w, ret);
-                       return ret;
-               }
-               config |= get_scalex_config(src_w, crtc_w);
-       }
+       ret = calc_scaley_steps(plane, pix_format, src_h, crtc_h, phasey_step);
+       if (ret)
+               return ret;
 
-       if ((src_h != crtc_h) || MDP_FORMAT_IS_YUV(format)) {
-               /* TODO calc vdecm */
-               ret = calc_scaley_steps(pix_format, src_h, crtc_h, phasey_step);
-               if (ret) {
-                       dev_err(dev, "Y scaling (%d -> %d) failed: %d\n",
-                                       src_h, crtc_h, ret);
-                       return ret;
-               }
-               config |= get_scaley_config(src_h, crtc_h);
-       }
+       /* TODO calc hdecm, vdecm */
+
+       /* SCALE is used to both scale and up-sample chroma components */
+       config |= get_scale_config(format->chroma_sample, src_w, crtc_w, true);
+       config |= get_scale_config(format->chroma_sample, src_h, crtc_h, false);
+       DBG("scale config = %x", config);
+
+       hflip = !!(pstate->rotation & BIT(DRM_REFLECT_X));
+       vflip = !!(pstate->rotation & BIT(DRM_REFLECT_Y));
 
        spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
 
@@ -535,7 +677,7 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
                        MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
                        MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
                        COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) |
-                       MDP5_PIPE_SRC_FORMAT_NUM_PLANES(format->fetch_type) |
+                       MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format->fetch_type) |
                        MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample));
 
        mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
@@ -545,29 +687,35 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
                        MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
 
        mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe),
+                       (hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) |
+                       (vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) |
                        MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS));
 
        /* not using secure mode: */
        mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
 
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
-                       phasex_step[0]);
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
-                       phasey_step[0]);
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
-                       phasex_step[1]);
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
-                       phasey_step[1]);
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
-                       MDP5_PIPE_DECIMATION_VERT(vdecm) |
-                       MDP5_PIPE_DECIMATION_HORZ(hdecm));
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config);
-
-       if (MDP_FORMAT_IS_YUV(format))
-               csc_enable(mdp5_kms, pipe,
-                               mdp_get_default_csc_cfg(CSC_YUV2RGB));
-       else
-               csc_disable(mdp5_kms, pipe);
+       if (mdp5_plane->caps & MDP_PIPE_CAP_SCALE) {
+               mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
+                               phasex_step[0]);
+               mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
+                               phasey_step[0]);
+               mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
+                               phasex_step[1]);
+               mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
+                               phasey_step[1]);
+               mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
+                               MDP5_PIPE_DECIMATION_VERT(vdecm) |
+                               MDP5_PIPE_DECIMATION_HORZ(hdecm));
+               mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config);
+       }
+
+       if (mdp5_plane->caps & MDP_PIPE_CAP_CSC) {
+               if (MDP_FORMAT_IS_YUV(format))
+                       csc_enable(mdp5_kms, pipe,
+                                       mdp_get_default_csc_cfg(CSC_YUV2RGB));
+               else
+                       csc_disable(mdp5_kms, pipe);
+       }
 
        set_scanout_locked(plane, fb);
 
@@ -602,9 +750,24 @@ uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
        return mdp5_plane->flush_mask;
 }
 
+/* called after vsync in thread context */
+void mdp5_plane_complete_commit(struct drm_plane *plane,
+       struct drm_plane_state *state)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(plane);
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       enum mdp5_pipe pipe = mdp5_plane->pipe;
+
+       if (!plane_enabled(plane->state)) {
+               DBG("%s: free SMP", mdp5_plane->name);
+               mdp5_smp_release(mdp5_kms->smp, pipe);
+       }
+}
+
 /* initialize plane */
 struct drm_plane *mdp5_plane_init(struct drm_device *dev,
-               enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset)
+               enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset,
+               uint32_t caps)
 {
        struct drm_plane *plane = NULL;
        struct mdp5_plane *mdp5_plane;
@@ -621,9 +784,11 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
 
        mdp5_plane->pipe = pipe;
        mdp5_plane->name = pipe2name(pipe);
+       mdp5_plane->caps = caps;
 
-       mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats,
-                       ARRAY_SIZE(mdp5_plane->formats));
+       mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
+               ARRAY_SIZE(mdp5_plane->formats),
+               !pipe_supports_yuv(mdp5_plane->caps));
 
        mdp5_plane->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
        mdp5_plane->reg_offset = reg_offset;
index 16702aecf0df714e211b8d7900fc06299e0e92f8..563cca972dcb92fad64dd22fdb78d301e9236b4b 100644 (file)
  * and CANNOT be re-allocated (eg: MMB0 and MMB1 both tied to RGB0).
  *
  * For each block that can be dynamically allocated, it can be either
- * free, or pending/in-use by a client. The updates happen in three steps:
+ *     free:
+ *     The block is free.
+ *
+ *     pending:
+ *     The block is allocated to some client and not free.
+ *
+ *     configured:
+ *     The block is allocated to some client, and assigned to that
+ *     client in MDP5_MDP_SMP_ALLOC registers.
+ *
+ *     inuse:
+ *     The block is being actively used by a client.
+ *
+ * The updates happen in the following steps:
  *
  *  1) mdp5_smp_request():
  *     When plane scanout is setup, calculate required number of
- *     blocks needed per client, and request.  Blocks not inuse or
- *     pending by any other client are added to client's pending
- *     set.
+ *     blocks needed per client, and request. Blocks neither inuse nor
+ *     configured nor pending by any other client are added to client's
+ *     pending set.
+ *     For shrinking, blocks in pending but not in configured can be freed
+ *     directly, but those already in configured will be freed later by
+ *     mdp5_smp_commit.
  *
  *  2) mdp5_smp_configure():
  *     As hw is programmed, before FLUSH, MDP5_MDP_SMP_ALLOC registers
  *     are configured for the union(pending, inuse)
+ *     Current pending is copied to configured.
+ *     It is assumed that mdp5_smp_request and mdp5_smp_configure not run
+ *     concurrently for the same pipe.
  *
  *  3) mdp5_smp_commit():
- *     After next vblank, copy pending -> inuse.  Optionally update
+ *     After next vblank, copy configured -> inuse.  Optionally update
  *     MDP5_SMP_ALLOC registers if there are newly unused blocks
  *
+ *  4) mdp5_smp_release():
+ *     Must be called after the pipe is disabled and no longer uses any SMB
+ *
  * On the next vblank after changes have been committed to hw, the
  * client's pending blocks become it's in-use blocks (and no-longer
  * in-use blocks become available to other clients).
@@ -68,6 +90,8 @@
 struct mdp5_smp {
        struct drm_device *dev;
 
+       const struct mdp5_smp_block *cfg;
+
        int blk_cnt;
        int blk_size;
 
@@ -77,6 +101,9 @@ struct mdp5_smp {
        struct mdp5_client_smp_state client_state[MAX_CLIENTS];
 };
 
+static void update_smp_state(struct mdp5_smp *smp,
+               u32 cid, mdp5_smp_state_t *assigned);
+
 static inline
 struct mdp5_kms *get_kms(struct mdp5_smp *smp)
 {
@@ -112,14 +139,12 @@ static int smp_request_block(struct mdp5_smp *smp,
                u32 cid, int nblks)
 {
        struct mdp5_kms *mdp5_kms = get_kms(smp);
-       const struct mdp5_cfg_hw *hw_cfg;
        struct mdp5_client_smp_state *ps = &smp->client_state[cid];
        int i, ret, avail, cur_nblks, cnt = smp->blk_cnt;
        int reserved;
        unsigned long flags;
 
-       hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
-       reserved = hw_cfg->smp.reserved[cid];
+       reserved = smp->cfg->reserved[cid];
 
        spin_lock_irqsave(&smp->state_lock, flags);
 
@@ -149,7 +174,12 @@ static int smp_request_block(struct mdp5_smp *smp,
                for (i = cur_nblks; i > nblks; i--) {
                        int blk = find_first_bit(ps->pending, cnt);
                        clear_bit(blk, ps->pending);
-                       /* don't clear in global smp_state until _commit() */
+
+                       /* clear in global smp_state if not in configured
+                        * otherwise until _commit()
+                        */
+                       if (!test_bit(blk, ps->configured))
+                               clear_bit(blk, smp->state);
                }
        }
 
@@ -179,12 +209,14 @@ static void set_fifo_thresholds(struct mdp5_smp *smp,
  * decimated width.  Ie. SMP buffering sits downstream of decimation (which
  * presumably happens during the dma from scanout buffer).
  */
-int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 width)
+int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe,
+               const struct mdp_format *format, u32 width, bool hdecim)
 {
        struct mdp5_kms *mdp5_kms = get_kms(smp);
        struct drm_device *dev = mdp5_kms->dev;
        int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg);
        int i, hsub, nplanes, nlines, nblks, ret;
+       u32 fmt = format->base.pixel_format;
 
        nplanes = drm_format_num_planes(fmt);
        hsub = drm_format_horz_chroma_subsampling(fmt);
@@ -192,6 +224,21 @@ int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 wid
        /* different if BWC (compressed framebuffer?) enabled: */
        nlines = 2;
 
+       /* Newer MDPs have split/packing logic, which fetches sub-sampled
+        * U and V components (splits them from Y if necessary) and packs
+        * them together, writes to SMP using a single client.
+        */
+       if ((rev > 0) && (format->chroma_sample > CHROMA_FULL)) {
+               fmt = DRM_FORMAT_NV24;
+               nplanes = 2;
+
+               /* if decimation is enabled, HW decimates less on the
+                * sub sampled chroma components
+                */
+               if (hdecim && (hsub > 1))
+                       hsub = 1;
+       }
+
        for (i = 0, nblks = 0; i < nplanes; i++) {
                int n, fetch_stride, cpp;
 
@@ -223,10 +270,33 @@ int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 wid
 /* Release SMP blocks for all clients of the pipe */
 void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe)
 {
-       int i, nblks;
+       int i;
+       unsigned long flags;
+       int cnt = smp->blk_cnt;
+
+       for (i = 0; i < pipe2nclients(pipe); i++) {
+               mdp5_smp_state_t assigned;
+               u32 cid = pipe2client(pipe, i);
+               struct mdp5_client_smp_state *ps = &smp->client_state[cid];
+
+               spin_lock_irqsave(&smp->state_lock, flags);
+
+               /* clear hw assignment */
+               bitmap_or(assigned, ps->inuse, ps->configured, cnt);
+               update_smp_state(smp, CID_UNUSED, &assigned);
+
+               /* free to global pool */
+               bitmap_andnot(smp->state, smp->state, ps->pending, cnt);
+               bitmap_andnot(smp->state, smp->state, assigned, cnt);
+
+               /* clear client's infor */
+               bitmap_zero(ps->pending, cnt);
+               bitmap_zero(ps->configured, cnt);
+               bitmap_zero(ps->inuse, cnt);
+
+               spin_unlock_irqrestore(&smp->state_lock, flags);
+       }
 
-       for (i = 0, nblks = 0; i < pipe2nclients(pipe); i++)
-               smp_request_block(smp, pipe2client(pipe, i), 0);
        set_fifo_thresholds(smp, pipe, 0);
 }
 
@@ -274,12 +344,20 @@ void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe)
                u32 cid = pipe2client(pipe, i);
                struct mdp5_client_smp_state *ps = &smp->client_state[cid];
 
-               bitmap_or(assigned, ps->inuse, ps->pending, cnt);
+               /*
+                * if vblank has not happened since last smp_configure
+                * skip the configure for now
+                */
+               if (!bitmap_equal(ps->inuse, ps->configured, cnt))
+                       continue;
+
+               bitmap_copy(ps->configured, ps->pending, cnt);
+               bitmap_or(assigned, ps->inuse, ps->configured, cnt);
                update_smp_state(smp, cid, &assigned);
        }
 }
 
-/* step #3: after vblank, copy pending -> inuse: */
+/* step #3: after vblank, copy configured -> inuse: */
 void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
 {
        int cnt = smp->blk_cnt;
@@ -295,7 +373,7 @@ void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
                 * using, which can be released and made available to other
                 * clients:
                 */
-               if (bitmap_andnot(released, ps->inuse, ps->pending, cnt)) {
+               if (bitmap_andnot(released, ps->inuse, ps->configured, cnt)) {
                        unsigned long flags;
 
                        spin_lock_irqsave(&smp->state_lock, flags);
@@ -306,7 +384,7 @@ void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
                        update_smp_state(smp, CID_UNUSED, &released);
                }
 
-               bitmap_copy(ps->inuse, ps->pending, cnt);
+               bitmap_copy(ps->inuse, ps->configured, cnt);
        }
 }
 
@@ -327,6 +405,7 @@ struct mdp5_smp *mdp5_smp_init(struct drm_device *dev, const struct mdp5_smp_blo
        }
 
        smp->dev = dev;
+       smp->cfg = cfg;
        smp->blk_cnt = cfg->mmb_count;
        smp->blk_size = cfg->mmb_size;
 
index e47179f635852a2f6ee546378200ce0a54a64499..20b87e800ea3b435dc7d2bded2eac6fec7caee26 100644 (file)
@@ -23,6 +23,7 @@
 
 struct mdp5_client_smp_state {
        mdp5_smp_state_t inuse;
+       mdp5_smp_state_t configured;
        mdp5_smp_state_t pending;
 };
 
@@ -38,7 +39,8 @@ struct mdp5_smp;
 struct mdp5_smp *mdp5_smp_init(struct drm_device *dev, const struct mdp5_smp_block *cfg);
 void  mdp5_smp_destroy(struct mdp5_smp *smp);
 
-int  mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 width);
+int  mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe,
+               const struct mdp_format *format, u32 width, bool hdecim);
 void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe);
 void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe);
 void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe);
index 641d036c5bcb620185e9bf3caaf2f120f7013168..4f792c4e40f426e09d4f02aeb22e8f938ef858b8 100644 (file)
@@ -8,17 +8,17 @@ 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            (  20915 bytes, from 2015-03-24 22:05:22)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2352 bytes, from 2015-04-12 15:02:42)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  35083 bytes, from 2015-04-12 15:04:03)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  22094 bytes, from 2015-05-12 12:45:23)
-- /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           (  29012 bytes, from 2015-05-12 12:45:23)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-12 12:45:23)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2576 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  36021 bytes, from 2015-07-09 22:10:24)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  26057 bytes, from 2015-08-14 21:47:57)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2015-05-20 20:03:14)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2015-05-20 20:03:07)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  29154 bytes, from 2015-08-10 21:25:43)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2015-05-20 20:03:14)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -46,7 +46,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 
 enum mdp_chroma_samp_type {
-       CHROMA_RGB = 0,
+       CHROMA_FULL = 0,
        CHROMA_H2V1 = 1,
        CHROMA_H1V2 = 2,
        CHROMA_420 = 3,
@@ -65,6 +65,10 @@ enum mdp_mixer_stage_id {
        STAGE1 = 3,
        STAGE2 = 4,
        STAGE3 = 5,
+       STAGE4 = 6,
+       STAGE5 = 7,
+       STAGE6 = 8,
+       STAGE_MAX = 8,
 };
 
 enum mdp_alpha_type {
index 7b0524dc187280121ad601d6d079a71cff2d7cbb..1c2caffc97e400b650b96a3e554fb5fe25d312a8 100644 (file)
@@ -71,7 +71,7 @@ static struct csc_cfg csc_convert[CSC_MAX] = {
        },
 };
 
-#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt, fp, cs) { \
+#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt, fp, cs, yuv) { \
                .base = { .pixel_format = DRM_FORMAT_ ## name }, \
                .bpc_a = BPC ## a ## A,                          \
                .bpc_r = BPC ## r,                               \
@@ -83,7 +83,8 @@ static struct csc_cfg csc_convert[CSC_MAX] = {
                .cpp = c,                                        \
                .unpack_count = cnt,                             \
                .fetch_type = fp,                                \
-               .chroma_sample = cs                              \
+               .chroma_sample = cs,                             \
+               .is_yuv = yuv,                                   \
 }
 
 #define BPC0A 0
@@ -95,30 +96,49 @@ static struct csc_cfg csc_convert[CSC_MAX] = {
 static const struct mdp_format formats[] = {
        /*  name      a  r  g  b   e0 e1 e2 e3  alpha   tight  cpp cnt ... */
        FMT(ARGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  true,   true,  4,  4,
-                       MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(ABGR8888, 8, 8, 8, 8,  2, 0, 1, 3,  true,   true,  4,  4,
-                       MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(RGBA8888, 8, 8, 8, 8,  3, 1, 0, 2,  true,   true,  4,  4,
-                       MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(BGRA8888, 8, 8, 8, 8,  3, 2, 0, 1,  true,   true,  4,  4,
-                       MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(XRGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  false,  true,  4,  4,
-                       MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(RGB888,   0, 8, 8, 8,  1, 0, 2, 0,  false,  true,  3,  3,
-                       MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(BGR888,   0, 8, 8, 8,  2, 0, 1, 0,  false,  true,  3,  3,
-                       MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(RGB565,   0, 5, 6, 5,  1, 0, 2, 0,  false,  true,  2,  3,
-                       MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(BGR565,   0, 5, 6, 5,  2, 0, 1, 0,  false,  true,  2,  3,
-                       MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
 
        /* --- RGB formats above / YUV formats below this line --- */
 
+       /* 2 plane YUV */
        FMT(NV12,     0, 8, 8, 8,  1, 2, 0, 0,  false,  true,  2, 2,
-                       MDP_PLANE_PSEUDO_PLANAR, CHROMA_420),
+                       MDP_PLANE_PSEUDO_PLANAR, CHROMA_420, true),
        FMT(NV21,     0, 8, 8, 8,  2, 1, 0, 0,  false,  true,  2, 2,
-                       MDP_PLANE_PSEUDO_PLANAR, CHROMA_420),
+                       MDP_PLANE_PSEUDO_PLANAR, CHROMA_420, true),
+       FMT(NV16,     0, 8, 8, 8,  1, 2, 0, 0,  false,  true,  2, 2,
+                       MDP_PLANE_PSEUDO_PLANAR, CHROMA_H2V1, true),
+       FMT(NV61,     0, 8, 8, 8,  2, 1, 0, 0,  false,  true,  2, 2,
+                       MDP_PLANE_PSEUDO_PLANAR, CHROMA_H2V1, true),
+       /* 1 plane YUV */
+       FMT(VYUY,     0, 8, 8, 8,  2, 0, 1, 0,  false,  true,  2, 4,
+                       MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
+       FMT(UYVY,     0, 8, 8, 8,  1, 0, 2, 0,  false,  true,  2, 4,
+                       MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
+       FMT(YUYV,     0, 8, 8, 8,  0, 1, 0, 2,  false,  true,  2, 4,
+                       MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
+       FMT(YVYU,     0, 8, 8, 8,  0, 2, 0, 1,  false,  true,  2, 4,
+                       MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
+       /* 3 plane YUV */
+       FMT(YUV420,   0, 8, 8, 8,  2, 1, 0, 0,  false,  true,  1, 1,
+                       MDP_PLANE_PLANAR, CHROMA_420, true),
+       FMT(YVU420,   0, 8, 8, 8,  1, 2, 0, 0,  false,  true,  1, 1,
+                       MDP_PLANE_PLANAR, CHROMA_420, true),
 };
 
 /*
index 1988c243f437eca2835fe8ce7a47166e735c2b8a..64287304054d1fce59753ecc4548f4debe0fba44 100644 (file)
@@ -39,7 +39,8 @@ static void update_irq(struct mdp_kms *mdp_kms)
        list_for_each_entry(irq, &mdp_kms->irq_list, node)
                irqmask |= irq->irqmask;
 
-       mdp_kms->funcs->set_irqmask(mdp_kms, irqmask);
+       mdp_kms->funcs->set_irqmask(mdp_kms, irqmask, mdp_kms->cur_irq_mask);
+       mdp_kms->cur_irq_mask = irqmask;
 }
 
 /* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder
index 2d3428cb74d024fda97d64a53ae02f8b6d7c4daf..46a94e7d50e21cad875d08edfdf46593c6b5707a 100644 (file)
@@ -30,7 +30,8 @@ struct mdp_kms;
 
 struct mdp_kms_funcs {
        struct msm_kms_funcs base;
-       void (*set_irqmask)(struct mdp_kms *mdp_kms, uint32_t irqmask);
+       void (*set_irqmask)(struct mdp_kms *mdp_kms, uint32_t irqmask,
+               uint32_t old_irqmask);
 };
 
 struct mdp_kms {
@@ -42,6 +43,7 @@ struct mdp_kms {
        bool in_irq;
        struct list_head irq_list;    /* list of mdp4_irq */
        uint32_t vblank_mask;         /* irq bits set for userspace vblank */
+       uint32_t cur_irq_mask;        /* current irq mask */
 };
 #define to_mdp_kms(x) container_of(x, struct mdp_kms, base)
 
@@ -90,13 +92,27 @@ struct mdp_format {
        uint8_t cpp, unpack_count;
        enum mdp_fetch_type fetch_type;
        enum mdp_chroma_samp_type chroma_sample;
+       bool is_yuv;
 };
 #define to_mdp_format(x) container_of(x, struct mdp_format, base)
-#define MDP_FORMAT_IS_YUV(mdp_format) ((mdp_format)->chroma_sample > CHROMA_RGB)
+#define MDP_FORMAT_IS_YUV(mdp_format) ((mdp_format)->is_yuv)
 
 uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats, bool rgb_only);
 const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format);
 
+/* MDP pipe capabilities */
+#define MDP_PIPE_CAP_HFLIP                     BIT(0)
+#define MDP_PIPE_CAP_VFLIP                     BIT(1)
+#define MDP_PIPE_CAP_SCALE                     BIT(2)
+#define MDP_PIPE_CAP_CSC                       BIT(3)
+#define MDP_PIPE_CAP_DECIMATION                        BIT(4)
+
+static inline bool pipe_supports_yuv(uint32_t pipe_caps)
+{
+       return (pipe_caps & MDP_PIPE_CAP_SCALE) &&
+               (pipe_caps & MDP_PIPE_CAP_CSC);
+}
+
 enum csc_type {
        CSC_RGB2RGB = 0,
        CSC_YUV2RGB,
index 1b22d8bfe142097f507435613b5bbd25311d4700..1ceb4f22dd8997a7b4e772d82e646abb1a87c7ff 100644 (file)
@@ -283,12 +283,8 @@ int msm_atomic_commit(struct drm_device *dev,
 
        timeout = ktime_add_ms(ktime_get(), 1000);
 
-       ret = msm_wait_fence_interruptable(dev, c->fence, &timeout);
-       if (ret) {
-               WARN_ON(ret);  // TODO unswap state back?  or??
-               commit_destroy(c);
-               return ret;
-       }
+       /* uninterruptible wait */
+       msm_wait_fence(dev, c->fence, &timeout, false);
 
        complete_commit(c);
 
index b7ef56ed8d1cf5280f942d83d2305672b414e0d8..0339c5d82d373b3038dca40ffc15a6ffcd58af55 100644 (file)
@@ -116,6 +116,65 @@ u32 msm_readl(const void __iomem *addr)
        return val;
 }
 
+struct vblank_event {
+       struct list_head node;
+       int crtc_id;
+       bool enable;
+};
+
+static void vblank_ctrl_worker(struct work_struct *work)
+{
+       struct msm_vblank_ctrl *vbl_ctrl = container_of(work,
+                                               struct msm_vblank_ctrl, work);
+       struct msm_drm_private *priv = container_of(vbl_ctrl,
+                                       struct msm_drm_private, vblank_ctrl);
+       struct msm_kms *kms = priv->kms;
+       struct vblank_event *vbl_ev, *tmp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vbl_ctrl->lock, flags);
+       list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
+               list_del(&vbl_ev->node);
+               spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
+
+               if (vbl_ev->enable)
+                       kms->funcs->enable_vblank(kms,
+                                               priv->crtcs[vbl_ev->crtc_id]);
+               else
+                       kms->funcs->disable_vblank(kms,
+                                               priv->crtcs[vbl_ev->crtc_id]);
+
+               kfree(vbl_ev);
+
+               spin_lock_irqsave(&vbl_ctrl->lock, flags);
+       }
+
+       spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
+}
+
+static int vblank_ctrl_queue_work(struct msm_drm_private *priv,
+                                       int crtc_id, bool enable)
+{
+       struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
+       struct vblank_event *vbl_ev;
+       unsigned long flags;
+
+       vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC);
+       if (!vbl_ev)
+               return -ENOMEM;
+
+       vbl_ev->crtc_id = crtc_id;
+       vbl_ev->enable = enable;
+
+       spin_lock_irqsave(&vbl_ctrl->lock, flags);
+       list_add_tail(&vbl_ev->node, &vbl_ctrl->event_list);
+       spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
+
+       queue_work(priv->wq, &vbl_ctrl->work);
+
+       return 0;
+}
+
 /*
  * DRM operations:
  */
@@ -125,6 +184,18 @@ static int msm_unload(struct drm_device *dev)
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_kms *kms = priv->kms;
        struct msm_gpu *gpu = priv->gpu;
+       struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
+       struct vblank_event *vbl_ev, *tmp;
+
+       /* We must cancel and cleanup any pending vblank enable/disable
+        * work before drm_irq_uninstall() to avoid work re-enabling an
+        * irq after uninstall has disabled it.
+        */
+       cancel_work_sync(&vbl_ctrl->work);
+       list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
+               list_del(&vbl_ev->node);
+               kfree(vbl_ev);
+       }
 
        drm_kms_helper_poll_fini(dev);
        drm_mode_config_cleanup(dev);
@@ -282,6 +353,9 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
 
        INIT_LIST_HEAD(&priv->inactive_list);
        INIT_LIST_HEAD(&priv->fence_cbs);
+       INIT_LIST_HEAD(&priv->vblank_ctrl.event_list);
+       INIT_WORK(&priv->vblank_ctrl.work, vblank_ctrl_worker);
+       spin_lock_init(&priv->vblank_ctrl.lock);
 
        drm_mode_config_init(dev);
 
@@ -331,10 +405,6 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
                }
        }
 
-       dev->mode_config.min_width = 0;
-       dev->mode_config.min_height = 0;
-       dev->mode_config.max_width = 2048;
-       dev->mode_config.max_height = 2048;
        dev->mode_config.funcs = &mode_config_funcs;
 
        ret = drm_vblank_init(dev, priv->num_crtcs);
@@ -468,7 +538,7 @@ static int msm_enable_vblank(struct drm_device *dev, int crtc_id)
        if (!kms)
                return -ENXIO;
        DBG("dev=%p, crtc=%d", dev, crtc_id);
-       return kms->funcs->enable_vblank(kms, priv->crtcs[crtc_id]);
+       return vblank_ctrl_queue_work(priv, crtc_id, true);
 }
 
 static void msm_disable_vblank(struct drm_device *dev, int crtc_id)
@@ -478,7 +548,7 @@ static void msm_disable_vblank(struct drm_device *dev, int crtc_id)
        if (!kms)
                return;
        DBG("dev=%p, crtc=%d", dev, crtc_id);
-       kms->funcs->disable_vblank(kms, priv->crtcs[crtc_id]);
+       vblank_ctrl_queue_work(priv, crtc_id, false);
 }
 
 /*
@@ -637,8 +707,8 @@ static void msm_debugfs_cleanup(struct drm_minor *minor)
  * Fences:
  */
 
-int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
-               ktime_t *timeout)
+int msm_wait_fence(struct drm_device *dev, uint32_t fence,
+               ktime_t *timeout , bool interruptible)
 {
        struct msm_drm_private *priv = dev->dev_private;
        int ret;
@@ -667,7 +737,12 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
                        remaining_jiffies = timespec_to_jiffies(&ts);
                }
 
-               ret = wait_event_interruptible_timeout(priv->fence_event,
+               if (interruptible)
+                       ret = wait_event_interruptible_timeout(priv->fence_event,
+                               fence_completed(dev, fence),
+                               remaining_jiffies);
+               else
+                       ret = wait_event_timeout(priv->fence_event,
                                fence_completed(dev, fence),
                                remaining_jiffies);
 
@@ -853,7 +928,7 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       return msm_wait_fence_interruptable(dev, args->fence, &timeout);
+       return msm_wait_fence(dev, args->fence, &timeout, true);
 }
 
 static const struct drm_ioctl_desc msm_ioctls[] = {
index e7c5ea125d45ed42ebaa043522a88b4bcb2c2e3f..3be7a56b14f1d85c478cc802b69ea441ba2f498e 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/list.h>
 #include <linux/iommu.h>
 #include <linux/types.h>
+#include <linux/of_graph.h>
 #include <asm/sizes.h>
 
 #ifndef CONFIG_OF
@@ -64,6 +65,19 @@ struct msm_file_private {
        int dummy;
 };
 
+enum msm_mdp_plane_property {
+       PLANE_PROP_ZPOS,
+       PLANE_PROP_ALPHA,
+       PLANE_PROP_PREMULTIPLIED,
+       PLANE_PROP_MAX_NUM
+};
+
+struct msm_vblank_ctrl {
+       struct work_struct work;
+       struct list_head event_list;
+       spinlock_t lock;
+};
+
 struct msm_drm_private {
 
        struct msm_kms *kms;
@@ -128,6 +142,9 @@ struct msm_drm_private {
        unsigned int num_connectors;
        struct drm_connector *connectors[8];
 
+       /* Properties */
+       struct drm_property *plane_property[PLANE_PROP_MAX_NUM];
+
        /* VRAM carveout, used when no IOMMU: */
        struct {
                unsigned long size;
@@ -137,6 +154,8 @@ struct msm_drm_private {
                 */
                struct drm_mm mm;
        } vram;
+
+       struct msm_vblank_ctrl vblank_ctrl;
 };
 
 struct msm_format {
@@ -164,8 +183,8 @@ int msm_atomic_commit(struct drm_device *dev,
 
 int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
 
-int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
-               ktime_t *timeout);
+int msm_wait_fence(struct drm_device *dev, uint32_t fence,
+               ktime_t *timeout, bool interruptible);
 int msm_queue_fence_cb(struct drm_device *dev,
                struct msm_fence_cb *cb, uint32_t fence);
 void msm_update_fence(struct drm_device *dev, uint32_t fence);
index 95f6532df02d9f9ab8eb8ff7da8b64a5f24a8349..f97a1964ef39494d9c9c2813482a33d4f7fc7a80 100644 (file)
@@ -43,11 +43,11 @@ static struct fb_ops msm_fb_ops = {
        /* Note: to properly handle manual update displays, we wrap the
         * basic fbdev ops which write to the framebuffer
         */
-       .fb_read = fb_sys_read,
-       .fb_write = fb_sys_write,
-       .fb_fillrect = sys_fillrect,
-       .fb_copyarea = sys_copyarea,
-       .fb_imageblit = sys_imageblit,
+       .fb_read = drm_fb_helper_sys_read,
+       .fb_write = drm_fb_helper_sys_write,
+       .fb_fillrect = drm_fb_helper_sys_fillrect,
+       .fb_copyarea = drm_fb_helper_sys_copyarea,
+       .fb_imageblit = drm_fb_helper_sys_imageblit,
        .fb_mmap = msm_fbdev_mmap,
 
        .fb_check_var = drm_fb_helper_check_var,
@@ -144,10 +144,10 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
                goto fail_unlock;
        }
 
-       fbi = framebuffer_alloc(0, dev->dev);
-       if (!fbi) {
+       fbi = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(fbi)) {
                dev_err(dev->dev, "failed to allocate fb info\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(fbi);
                goto fail_unlock;
        }
 
@@ -155,7 +155,6 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
 
        fbdev->fb = fb;
        helper->fb = fb;
-       helper->fbdev = fbi;
 
        fbi->par = helper;
        fbi->flags = FBINFO_DEFAULT;
@@ -163,12 +162,6 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
 
        strcpy(fbi->fix.id, "msm");
 
-       ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto fail_unlock;
-       }
-
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
        drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
@@ -191,7 +184,6 @@ fail_unlock:
 fail:
 
        if (ret) {
-               framebuffer_release(fbi);
                if (fb) {
                        drm_framebuffer_unregister_private(fb);
                        drm_framebuffer_remove(fb);
@@ -266,17 +258,11 @@ void msm_fbdev_free(struct drm_device *dev)
        struct msm_drm_private *priv = dev->dev_private;
        struct drm_fb_helper *helper = priv->fbdev;
        struct msm_fbdev *fbdev;
-       struct fb_info *fbi;
 
        DBG();
 
-       fbi = helper->fbdev;
-
-       /* only cleanup framebuffer if it is present */
-       if (fbi) {
-               unregister_framebuffer(fbi);
-               framebuffer_release(fbi);
-       }
+       drm_fb_helper_unregister_fbi(helper);
+       drm_fb_helper_release_fbi(helper);
 
        drm_fb_helper_fini(helper);
 
index f211b80e3a1e0604489b1ed91a65e4e1b489b894..c76cc853b08a57effec626b8c6f537b270ca61ac 100644 (file)
@@ -460,7 +460,7 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout)
                if (op & MSM_PREP_NOSYNC)
                        timeout = NULL;
 
-               ret = msm_wait_fence_interruptable(dev, fence, timeout);
+               ret = msm_wait_fence(dev, fence, timeout, true);
        }
 
        /* TODO cache maintenance */
index dd7a7ab603e2c202ea297575fab0aba003234f5b..831461bc98a549e8a3627cbd1cf5a1b4a3250c7b 100644 (file)
 struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj)
 {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
-       BUG_ON(!msm_obj->sgt);  /* should have already pinned! */
-       return msm_obj->sgt;
+       int npages = obj->size >> PAGE_SHIFT;
+
+       if (WARN_ON(!msm_obj->pages))  /* should have already pinned! */
+               return NULL;
+
+       return drm_prime_pages_to_sg(msm_obj->pages, npages);
 }
 
 void *msm_gem_prime_vmap(struct drm_gem_object *obj)
index 9f2498571d0953801e30108e439a473b4afff71c..5f6ea1873f517d1bbf357690b9fa817427ce91f1 100644 (file)
@@ -261,7 +261,7 @@ nv10_overlay_init(struct drm_device *device)
 {
        struct nouveau_drm *drm = nouveau_drm(device);
        struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL);
-       int num_formats = ARRAY_SIZE(formats);
+       unsigned int num_formats = ARRAY_SIZE(formats);
        int ret;
 
        if (!plane)
index 3162040bc3148b2157249dd29f945d8d05585812..1f26eba245d10b624ecdbab392ed7ef30f0d163d 100644 (file)
@@ -919,7 +919,7 @@ nouveau_connector_funcs_lvds = {
        .force = nouveau_connector_force
 };
 
-static void
+static int
 nouveau_connector_dp_dpms(struct drm_connector *connector, int mode)
 {
        struct nouveau_encoder *nv_encoder = NULL;
@@ -938,7 +938,7 @@ nouveau_connector_dp_dpms(struct drm_connector *connector, int mode)
                }
        }
 
-       drm_helper_connector_dpms(connector, mode);
+       return drm_helper_connector_dpms(connector, mode);
 }
 
 static const struct drm_connector_funcs
index 36b40c9252b5df3f7aac5608957f78e9c887aa4f..109b8262dc85942ac54720c57682402c161d435e 100644 (file)
@@ -128,6 +128,7 @@ nouveau_cli_destroy(struct nouveau_cli *cli)
        nvkm_vm_ref(NULL, &nvxx_client(&cli->base)->vm, NULL);
        nvif_client_fini(&cli->base);
        usif_client_fini(cli);
+       kfree(cli);
 }
 
 static void
@@ -865,8 +866,10 @@ nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv)
 
        pm_runtime_get_sync(dev->dev);
 
+       mutex_lock(&cli->mutex);
        if (cli->abi16)
                nouveau_abi16_fini(cli->abi16);
+       mutex_unlock(&cli->mutex);
 
        mutex_lock(&drm->client.mutex);
        list_del(&cli->head);
index 6751553abe4afe4bc408cd08863a7981b858bece..2791701685dc82bf4e2655ce3ea8ea6c3b278e49 100644 (file)
@@ -84,7 +84,7 @@ nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 
        if (ret != -ENODEV)
                nouveau_fbcon_gpu_lockup(info);
-       cfb_fillrect(info, rect);
+       drm_fb_helper_cfb_fillrect(info, rect);
 }
 
 static void
@@ -116,7 +116,7 @@ nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
 
        if (ret != -ENODEV)
                nouveau_fbcon_gpu_lockup(info);
-       cfb_copyarea(info, image);
+       drm_fb_helper_cfb_copyarea(info, image);
 }
 
 static void
@@ -148,7 +148,7 @@ nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
 
        if (ret != -ENODEV)
                nouveau_fbcon_gpu_lockup(info);
-       cfb_imageblit(info, image);
+       drm_fb_helper_cfb_imageblit(info, image);
 }
 
 static int
@@ -197,9 +197,9 @@ static struct fb_ops nouveau_fbcon_sw_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = drm_fb_helper_set_par,
-       .fb_fillrect = cfb_fillrect,
-       .fb_copyarea = cfb_copyarea,
-       .fb_imageblit = cfb_imageblit,
+       .fb_fillrect = drm_fb_helper_cfb_fillrect,
+       .fb_copyarea = drm_fb_helper_cfb_copyarea,
+       .fb_imageblit = drm_fb_helper_cfb_imageblit,
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
@@ -319,7 +319,6 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
        struct nouveau_channel *chan;
        struct nouveau_bo *nvbo;
        struct drm_mode_fb_cmd2 mode_cmd;
-       struct pci_dev *pdev = dev->pdev;
        int size, ret;
 
        mode_cmd.width = sizes->surface_width;
@@ -365,20 +364,13 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
 
        mutex_lock(&dev->struct_mutex);
 
-       info = framebuffer_alloc(0, &pdev->dev);
-       if (!info) {
-               ret = -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info)) {
+               ret = PTR_ERR(info);
                goto out_unlock;
        }
        info->skip_vt_switch = 1;
 
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               framebuffer_release(info);
-               goto out_unlock;
-       }
-
        info->par = fbcon;
 
        nouveau_framebuffer_init(dev, &fbcon->nouveau_fb, &mode_cmd, nvbo);
@@ -388,7 +380,6 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
 
        /* setup helper */
        fbcon->helper.fb = fb;
-       fbcon->helper.fbdev = info;
 
        strcpy(info->fix.id, "nouveaufb");
        if (!chan)
@@ -450,15 +441,9 @@ static int
 nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
 {
        struct nouveau_framebuffer *nouveau_fb = &fbcon->nouveau_fb;
-       struct fb_info *info;
 
-       if (fbcon->helper.fbdev) {
-               info = fbcon->helper.fbdev;
-               unregister_framebuffer(info);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&fbcon->helper);
+       drm_fb_helper_release_fbi(&fbcon->helper);
 
        if (nouveau_fb->nvbo) {
                nouveau_bo_unmap(nouveau_fb->nvbo);
@@ -496,7 +481,7 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
                console_lock();
                if (state == FBINFO_STATE_RUNNING)
                        nouveau_fbcon_accel_restore(dev);
-               fb_set_suspend(drm->fbcon->helper.fbdev, state);
+               drm_fb_helper_set_suspend(&drm->fbcon->helper, state);
                if (state != FBINFO_STATE_RUNNING)
                        nouveau_fbcon_accel_save_disable(dev);
                console_unlock();
index 775277f1edb0a4ae4c1a2862418827878710ddb8..dcfbbfaf1739781724e312a4fc15cded1298358d 100644 (file)
@@ -92,6 +92,8 @@ static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu)
        return 0;
 }
 
+#if IS_ENABLED(CONFIG_IOMMU_API)
+
 static void nouveau_platform_probe_iommu(struct device *dev,
                                         struct nouveau_platform_gpu *gpu)
 {
@@ -158,6 +160,20 @@ static void nouveau_platform_remove_iommu(struct device *dev,
        }
 }
 
+#else
+
+static void nouveau_platform_probe_iommu(struct device *dev,
+                                        struct nouveau_platform_gpu *gpu)
+{
+}
+
+static void nouveau_platform_remove_iommu(struct device *dev,
+                                         struct nouveau_platform_gpu *gpu)
+{
+}
+
+#endif
+
 static int nouveau_platform_probe(struct platform_device *pdev)
 {
        struct nouveau_platform_gpu *gpu;
index 18f4497157885a897a9cbec14c390d397a02ca25..737e8f976a98356cf95984f86aa80ebf191c8a8e 100644 (file)
@@ -175,15 +175,24 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
        node->page_shift = 12;
 
        switch (drm->device.info.family) {
+       case NV_DEVICE_INFO_V0_TNT:
+       case NV_DEVICE_INFO_V0_CELSIUS:
+       case NV_DEVICE_INFO_V0_KELVIN:
+       case NV_DEVICE_INFO_V0_RANKINE:
+       case NV_DEVICE_INFO_V0_CURIE:
+               break;
        case NV_DEVICE_INFO_V0_TESLA:
                if (drm->device.info.chipset != 0x50)
                        node->memtype = (nvbo->tile_flags & 0x7f00) >> 8;
                break;
        case NV_DEVICE_INFO_V0_FERMI:
        case NV_DEVICE_INFO_V0_KEPLER:
+       case NV_DEVICE_INFO_V0_MAXWELL:
                node->memtype = (nvbo->tile_flags & 0xff00) >> 8;
                break;
        default:
+               NV_WARN(drm, "%s: unhandled family type %x\n", __func__,
+                       drm->device.info.family);
                break;
        }
 
@@ -424,10 +433,8 @@ nouveau_ttm_init(struct nouveau_drm *drm)
 void
 nouveau_ttm_fini(struct nouveau_drm *drm)
 {
-       mutex_lock(&drm->dev->struct_mutex);
        ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM);
        ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT);
-       mutex_unlock(&drm->dev->struct_mutex);
 
        ttm_bo_device_release(&drm->ttm.bdev);
 
index 4ef602c5469d2563ee89d4153f0315abdc485a20..495c57644ced91e4a45c7b8b6205fff7d32ff8ae 100644 (file)
@@ -203,7 +203,7 @@ nv04_fbcon_accel_init(struct fb_info *info)
        if (ret)
                return ret;
 
-       if (RING_SPACE(chan, 49)) {
+       if (RING_SPACE(chan, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) {
                nouveau_fbcon_gpu_lockup(info);
                return 0;
        }
index 7da7958556a3abe68f94eac820c62aa8b41a923a..981342d142ff61b6c6292fc14399eb7a43ad08a6 100644 (file)
@@ -979,7 +979,7 @@ nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
 {
        struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
 
-       if (show && nv_crtc->cursor.nvbo)
+       if (show && nv_crtc->cursor.nvbo && nv_crtc->base.enabled)
                nv50_crtc_cursor_show(nv_crtc);
        else
                nv50_crtc_cursor_hide(nv_crtc);
index 394c89abcc97d92cf1b0352ea6e060b9ee011027..901130b0607291da4d08401f82e6ed05688c84b5 100644 (file)
@@ -188,7 +188,7 @@ nv50_fbcon_accel_init(struct fb_info *info)
        if (ret)
                return ret;
 
-       ret = RING_SPACE(chan, 59);
+       ret = RING_SPACE(chan, 58);
        if (ret) {
                nouveau_fbcon_gpu_lockup(info);
                return ret;
@@ -252,6 +252,7 @@ nv50_fbcon_accel_init(struct fb_info *info)
        OUT_RING(chan, info->var.yres_virtual);
        OUT_RING(chan, upper_32_bits(fb->vma.offset));
        OUT_RING(chan, lower_32_bits(fb->vma.offset));
+       FIRE_RING(chan);
 
        return 0;
 }
index 61246677e8dcdd901119a84d5bc4e6c09287978b..fcd2e5f27bb9539ba113e790222713b10127f825 100644 (file)
@@ -188,7 +188,7 @@ nvc0_fbcon_accel_init(struct fb_info *info)
                return -EINVAL;
        }
 
-       ret = RING_SPACE(chan, 60);
+       ret = RING_SPACE(chan, 58);
        if (ret) {
                WARN_ON(1);
                nouveau_fbcon_gpu_lockup(info);
index 9ef6728c528d999ef625a9c1472de95c0c02ba24..7f2f05f78cc8cb7a17e7c7f2445c741981c9389a 100644 (file)
@@ -809,7 +809,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
                case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
                default:
                        nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
-                       return 0x0000;
+                       return NULL;
                }
        }
 
index 5606c25e5d02998fc415a5b9705d9a40868f2a10..ca11ddb6ed467588ebe5cb98e359b91e07da92c4 100644 (file)
@@ -663,6 +663,37 @@ gf100_gr_zbc_init(struct gf100_gr_priv *priv)
                gf100_gr_zbc_clear_depth(priv, index);
 }
 
+/**
+ * Wait until GR goes idle. GR is considered idle if it is disabled by the
+ * MC (0x200) register, or GR is not busy and a context switch is not in
+ * progress.
+ */
+int
+gf100_gr_wait_idle(struct gf100_gr_priv *priv)
+{
+       unsigned long end_jiffies = jiffies + msecs_to_jiffies(2000);
+       bool gr_enabled, ctxsw_active, gr_busy;
+
+       do {
+               /*
+                * required to make sure FIFO_ENGINE_STATUS (0x2640) is
+                * up-to-date
+                */
+               nv_rd32(priv, 0x400700);
+
+               gr_enabled = nv_rd32(priv, 0x200) & 0x1000;
+               ctxsw_active = nv_rd32(priv, 0x2640) & 0x8000;
+               gr_busy = nv_rd32(priv, 0x40060c) & 0x1;
+
+               if (!gr_enabled || (!gr_busy && !ctxsw_active))
+                       return 0;
+       } while (time_before(jiffies, end_jiffies));
+
+       nv_error(priv, "wait for idle timeout (en: %d, ctxsw: %d, busy: %d)\n",
+                gr_enabled, ctxsw_active, gr_busy);
+       return -EAGAIN;
+}
+
 void
 gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
 {
@@ -699,7 +730,13 @@ gf100_gr_icmd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
 
                while (addr < next) {
                        nv_wr32(priv, 0x400200, addr);
-                       nv_wait(priv, 0x400700, 0x00000002, 0x00000000);
+                       /**
+                        * Wait for GR to go idle after submitting a
+                        * GO_IDLE bundle
+                        */
+                       if ((addr & 0xffff) == 0xe100)
+                               gf100_gr_wait_idle(priv);
+                       nv_wait(priv, 0x400700, 0x00000004, 0x00000000);
                        addr += init->pitch;
                }
        }
index 8af1a89eda84d13436b0345301a3e767cc710c19..c9533fdac4fc85a2b0189429d6564cbc119734a7 100644 (file)
@@ -181,6 +181,7 @@ struct gf100_gr_oclass {
        int ppc_nr;
 };
 
+int  gf100_gr_wait_idle(struct gf100_gr_priv *);
 void gf100_gr_mmio(struct gf100_gr_priv *, const struct gf100_gr_pack *);
 void gf100_gr_icmd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
 void gf100_gr_mthd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
index 2006c445938d9493773ef2dbf9bb07d045a67b96..4cf36a3aa81460c2c062b6cc41e70571530c1eb8 100644 (file)
@@ -332,9 +332,12 @@ static void
 nvkm_perfctx_dtor(struct nvkm_object *object)
 {
        struct nvkm_pm *ppm = (void *)object->engine;
+       struct nvkm_perfctx *ctx = (void *)object;
+
        mutex_lock(&nv_subdev(ppm)->mutex);
-       nvkm_engctx_destroy(&ppm->context->base);
-       ppm->context = NULL;
+       nvkm_engctx_destroy(&ctx->base);
+       if (ppm->context == ctx)
+               ppm->context = NULL;
        mutex_unlock(&nv_subdev(ppm)->mutex);
 }
 
@@ -355,12 +358,11 @@ nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        mutex_lock(&nv_subdev(ppm)->mutex);
        if (ppm->context == NULL)
                ppm->context = ctx;
-       mutex_unlock(&nv_subdev(ppm)->mutex);
-
        if (ctx != ppm->context)
-               return -EBUSY;
+               ret = -EBUSY;
+       mutex_unlock(&nv_subdev(ppm)->mutex);
 
-       return 0;
+       return ret;
 }
 
 struct nvkm_oclass
index f67cdae1e90a599a04c46dd7a654102a7731bdf0..f4611e3f097187002e68dc54af44c45bfd0006d9 100644 (file)
@@ -1284,6 +1284,44 @@ init_zm_reg_sequence(struct nvbios_init *init)
        }
 }
 
+/**
+ * INIT_PLL_INDIRECT - opcode 0x59
+ *
+ */
+static void
+init_pll_indirect(struct nvbios_init *init)
+{
+       struct nvkm_bios *bios = init->bios;
+       u32  reg = nv_ro32(bios, init->offset + 1);
+       u16 addr = nv_ro16(bios, init->offset + 5);
+       u32 freq = (u32)nv_ro16(bios, addr) * 1000;
+
+       trace("PLL_INDIRECT\tR[0x%06x] =PLL= VBIOS[%04x] = %dkHz\n",
+             reg, addr, freq);
+       init->offset += 7;
+
+       init_prog_pll(init, reg, freq);
+}
+
+/**
+ * INIT_ZM_REG_INDIRECT - opcode 0x5a
+ *
+ */
+static void
+init_zm_reg_indirect(struct nvbios_init *init)
+{
+       struct nvkm_bios *bios = init->bios;
+       u32  reg = nv_ro32(bios, init->offset + 1);
+       u16 addr = nv_ro16(bios, init->offset + 5);
+       u32 data = nv_ro32(bios, addr);
+
+       trace("ZM_REG_INDIRECT\tR[0x%06x] = VBIOS[0x%04x] = 0x%08x\n",
+             reg, addr, data);
+       init->offset += 7;
+
+       init_wr32(init, addr, data);
+}
+
 /**
  * INIT_SUB_DIRECT - opcode 0x5b
  *
@@ -2145,6 +2183,8 @@ static struct nvbios_init_opcode {
        [0x56] = { init_condition_time },
        [0x57] = { init_ltime },
        [0x58] = { init_zm_reg_sequence },
+       [0x59] = { init_pll_indirect },
+       [0x5a] = { init_zm_reg_indirect },
        [0x5b] = { init_sub_direct },
        [0x5c] = { init_jump },
        [0x5e] = { init_i2c_if },
index 822d32a28d6e15a38f8c9db722288c27c9349d41..065e9f5c8db98a0a2b70b5b2d4a203d350899465 100644 (file)
@@ -180,7 +180,8 @@ gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz,
               struct gt215_clk_info *info)
 {
        struct gt215_clk_priv *priv = (void *)clock;
-       u32 oclk, sclk, sdiv, diff;
+       u32 oclk, sclk, sdiv;
+       s32 diff;
 
        info->clk = 0;
 
index c0fdb89e74ac4a41944e2d7c2f41ca3daa6c4ed6..24dcdfb58a8d852039317a5017ee34dcc9cf3039 100644 (file)
@@ -38,6 +38,14 @@ gk20a_ibus_init_priv_ring(struct gk20a_ibus_priv *priv)
        nv_wr32(priv, 0x12004c, 0x4);
        nv_wr32(priv, 0x122204, 0x2);
        nv_rd32(priv, 0x122204);
+
+       /*
+        * Bug: increase clock timeout to avoid operation failure at high
+        * gpcclk rate.
+        */
+       nv_wr32(priv, 0x122354, 0x800);
+       nv_wr32(priv, 0x128328, 0x800);
+       nv_wr32(priv, 0x124320, 0x800);
 }
 
 static void
index 80614f1b207474ae407251d6811add96925e8241..282143f49d72e60ba5c66f79fc818ca3b37ea942 100644 (file)
@@ -50,7 +50,12 @@ nv04_instobj_dtor(struct nvkm_object *object)
 {
        struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object);
        struct nv04_instobj_priv *node = (void *)object;
+       struct nvkm_subdev *subdev = (void *)priv;
+
+       mutex_lock(&subdev->mutex);
        nvkm_mm_free(&priv->heap, &node->mem);
+       mutex_unlock(&subdev->mutex);
+
        nvkm_instobj_destroy(&node->base);
 }
 
@@ -62,6 +67,7 @@ nv04_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        struct nv04_instmem_priv *priv = (void *)nvkm_instmem(parent);
        struct nv04_instobj_priv *node;
        struct nvkm_instobj_args *args = data;
+       struct nvkm_subdev *subdev = (void *)priv;
        int ret;
 
        if (!args->align)
@@ -72,8 +78,10 @@ nv04_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        if (ret)
                return ret;
 
+       mutex_lock(&subdev->mutex);
        ret = nvkm_mm_head(&priv->heap, 0, 1, args->size, args->size,
                           args->align, &node->mem);
+       mutex_unlock(&subdev->mutex);
        if (ret)
                return ret;
 
index 23d9c928cdc91b44c20efd05fd361e85f20089f3..9a4ba4f035673e859c6687fcc76bc507b4ab8996 100644 (file)
@@ -388,11 +388,13 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
        copy_timings_drm_to_omap(&omap_crtc->timings, mode);
 }
 
-static void omap_crtc_atomic_begin(struct drm_crtc *crtc)
+static void omap_crtc_atomic_begin(struct drm_crtc *crtc,
+                                  struct drm_crtc_state *old_crtc_state)
 {
 }
 
-static void omap_crtc_atomic_flush(struct drm_crtc *crtc)
+static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
+                                  struct drm_crtc_state *old_crtc_state)
 {
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 
index 720d16bce7e82b790a7aff17f5bbec94b6df18fe..b8e4cdec28c363c7e5c10881be4ea61461023ace 100644 (file)
@@ -86,11 +86,11 @@ static struct fb_ops omap_fb_ops = {
        /* Note: to properly handle manual update displays, we wrap the
         * basic fbdev ops which write to the framebuffer
         */
-       .fb_read = fb_sys_read,
-       .fb_write = fb_sys_write,
-       .fb_fillrect = sys_fillrect,
-       .fb_copyarea = sys_copyarea,
-       .fb_imageblit = sys_imageblit,
+       .fb_read = drm_fb_helper_sys_read,
+       .fb_write = drm_fb_helper_sys_write,
+       .fb_fillrect = drm_fb_helper_sys_fillrect,
+       .fb_copyarea = drm_fb_helper_sys_copyarea,
+       .fb_imageblit = drm_fb_helper_sys_imageblit,
 
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = drm_fb_helper_set_par,
@@ -179,10 +179,10 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 
        mutex_lock(&dev->struct_mutex);
 
-       fbi = framebuffer_alloc(0, dev->dev);
-       if (!fbi) {
+       fbi = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(fbi)) {
                dev_err(dev->dev, "failed to allocate fb info\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(fbi);
                goto fail_unlock;
        }
 
@@ -190,7 +190,6 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 
        fbdev->fb = fb;
        helper->fb = fb;
-       helper->fbdev = fbi;
 
        fbi->par = helper;
        fbi->flags = FBINFO_DEFAULT;
@@ -198,12 +197,6 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 
        strcpy(fbi->fix.id, MODULE_NAME);
 
-       ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto fail_unlock;
-       }
-
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
        drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
@@ -236,8 +229,9 @@ fail_unlock:
 fail:
 
        if (ret) {
-               if (fbi)
-                       framebuffer_release(fbi);
+
+               drm_fb_helper_release_fbi(helper);
+
                if (fb) {
                        drm_framebuffer_unregister_private(fb);
                        drm_framebuffer_remove(fb);
@@ -312,17 +306,11 @@ void omap_fbdev_free(struct drm_device *dev)
        struct omap_drm_private *priv = dev->dev_private;
        struct drm_fb_helper *helper = priv->fbdev;
        struct omap_fbdev *fbdev;
-       struct fb_info *fbi;
 
        DBG();
 
-       fbi = helper->fbdev;
-
-       /* only cleanup framebuffer if it is present */
-       if (fbi) {
-               unregister_framebuffer(fbi);
-               framebuffer_release(fbi);
-       }
+       drm_fb_helper_unregister_fbi(helper);
+       drm_fb_helper_release_fbi(helper);
 
        drm_fb_helper_fini(helper);
 
index 6d64c7bb908bcdaa403f7e7ec68646135ab710b9..7d4704b1292b5b700124941102c2a5594a88275a 100644 (file)
@@ -18,13 +18,21 @@ config DRM_PANEL_SIMPLE
          that it can be automatically turned off when the panel goes into a
          low power state.
 
-config DRM_PANEL_LD9040
-       tristate "LD9040 RGB/SPI panel"
+config DRM_PANEL_SAMSUNG_LD9040
+       tristate "Samsung LD9040 RGB/SPI panel"
        depends on OF && SPI
        select VIDEOMODE_HELPERS
 
-config DRM_PANEL_S6E8AA0
-       tristate "S6E8AA0 DSI video mode panel"
+config DRM_PANEL_LG_LG4573
+       tristate "LG4573 RGB/SPI panel"
+       depends on OF && SPI
+       select VIDEOMODE_HELPERS
+       help
+         Say Y here if you want to enable support for LG4573 RGB panel.
+         To compile this driver as a module, choose M here.
+
+config DRM_PANEL_SAMSUNG_S6E8AA0
+       tristate "Samsung S6E8AA0 DSI video mode panel"
        depends on OF
        select DRM_MIPI_DSI
        select VIDEOMODE_HELPERS
index 4b2a0430804b1813ed02bc713e61590e7a62d849..d0f016dd7ddb530b6f579095c15990d49cad45d1 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
-obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o
-obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o
+obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
 obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
diff --git a/drivers/gpu/drm/panel/panel-lg-lg4573.c b/drivers/gpu/drm/panel/panel-lg-lg4573.c
new file mode 100644 (file)
index 0000000..a7b4939
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2015 Heiko Schocher <hs@denx.de>
+ *
+ * from:
+ * drivers/gpu/drm/panel/panel-ld9040.c
+ * ld9040 AMOLED LCD drm_panel driver.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ * Derived from drivers/video/backlight/ld9040.c
+ *
+ * Andrzej Hajda <a.hajda@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <drm/drmP.h>
+#include <drm/drm_panel.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <video/mipi_display.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+struct lg4573 {
+       struct drm_panel panel;
+       struct spi_device *spi;
+       struct videomode vm;
+};
+
+static inline struct lg4573 *panel_to_lg4573(struct drm_panel *panel)
+{
+       return container_of(panel, struct lg4573, panel);
+}
+
+static int lg4573_spi_write_u16(struct lg4573 *ctx, u16 data)
+{
+       struct spi_transfer xfer = {
+               .len = 2,
+       };
+       u16 temp = cpu_to_be16(data);
+       struct spi_message msg;
+
+       dev_dbg(ctx->panel.dev, "writing data: %x\n", data);
+       xfer.tx_buf = &temp;
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       return spi_sync(ctx->spi, &msg);
+}
+
+static int lg4573_spi_write_u16_array(struct lg4573 *ctx, const u16 *buffer,
+                                     unsigned int count)
+{
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < count; i++) {
+               ret = lg4573_spi_write_u16(ctx, buffer[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int lg4573_spi_write_dcs(struct lg4573 *ctx, u8 dcs)
+{
+       return lg4573_spi_write_u16(ctx, (0x70 << 8 | dcs));
+}
+
+static int lg4573_display_on(struct lg4573 *ctx)
+{
+       int ret;
+
+       ret = lg4573_spi_write_dcs(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
+       if (ret)
+               return ret;
+
+       msleep(5);
+
+       return lg4573_spi_write_dcs(ctx, MIPI_DCS_SET_DISPLAY_ON);
+}
+
+static int lg4573_display_off(struct lg4573 *ctx)
+{
+       int ret;
+
+       ret = lg4573_spi_write_dcs(ctx, MIPI_DCS_SET_DISPLAY_OFF);
+       if (ret)
+               return ret;
+
+       msleep(120);
+
+       return lg4573_spi_write_dcs(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
+}
+
+static int lg4573_display_mode_settings(struct lg4573 *ctx)
+{
+       static const u16 display_mode_settings[] = {
+               0x703A, 0x7270, 0x70B1, 0x7208,
+               0x723B, 0x720F, 0x70B2, 0x7200,
+               0x72C8, 0x70B3, 0x7200, 0x70B4,
+               0x7200, 0x70B5, 0x7242, 0x7210,
+               0x7210, 0x7200, 0x7220, 0x70B6,
+               0x720B, 0x720F, 0x723C, 0x7213,
+               0x7213, 0x72E8, 0x70B7, 0x7246,
+               0x7206, 0x720C, 0x7200, 0x7200,
+       };
+
+       dev_dbg(ctx->panel.dev, "transfer display mode settings\n");
+       return lg4573_spi_write_u16_array(ctx, display_mode_settings,
+                                         ARRAY_SIZE(display_mode_settings));
+}
+
+static int lg4573_power_settings(struct lg4573 *ctx)
+{
+       static const u16 power_settings[] = {
+               0x70C0, 0x7201, 0x7211, 0x70C3,
+               0x7207, 0x7203, 0x7204, 0x7204,
+               0x7204, 0x70C4, 0x7212, 0x7224,
+               0x7218, 0x7218, 0x7202, 0x7249,
+               0x70C5, 0x726F, 0x70C6, 0x7241,
+               0x7263,
+       };
+
+       dev_dbg(ctx->panel.dev, "transfer power settings\n");
+       return lg4573_spi_write_u16_array(ctx, power_settings,
+                                         ARRAY_SIZE(power_settings));
+}
+
+static int lg4573_gamma_settings(struct lg4573 *ctx)
+{
+       static const u16 gamma_settings[] = {
+               0x70D0, 0x7203, 0x7207, 0x7273,
+               0x7235, 0x7200, 0x7201, 0x7220,
+               0x7200, 0x7203, 0x70D1, 0x7203,
+               0x7207, 0x7273, 0x7235, 0x7200,
+               0x7201, 0x7220, 0x7200, 0x7203,
+               0x70D2, 0x7203, 0x7207, 0x7273,
+               0x7235, 0x7200, 0x7201, 0x7220,
+               0x7200, 0x7203, 0x70D3, 0x7203,
+               0x7207, 0x7273, 0x7235, 0x7200,
+               0x7201, 0x7220, 0x7200, 0x7203,
+               0x70D4, 0x7203, 0x7207, 0x7273,
+               0x7235, 0x7200, 0x7201, 0x7220,
+               0x7200, 0x7203, 0x70D5, 0x7203,
+               0x7207, 0x7273, 0x7235, 0x7200,
+               0x7201, 0x7220, 0x7200, 0x7203,
+       };
+
+       dev_dbg(ctx->panel.dev, "transfer gamma settings\n");
+       return lg4573_spi_write_u16_array(ctx, gamma_settings,
+                                         ARRAY_SIZE(gamma_settings));
+}
+
+static int lg4573_init(struct lg4573 *ctx)
+{
+       int ret;
+
+       dev_dbg(ctx->panel.dev, "initializing LCD\n");
+
+       ret = lg4573_display_mode_settings(ctx);
+       if (ret)
+               return ret;
+
+       ret = lg4573_power_settings(ctx);
+       if (ret)
+               return ret;
+
+       return lg4573_gamma_settings(ctx);
+}
+
+static int lg4573_power_on(struct lg4573 *ctx)
+{
+       return lg4573_display_on(ctx);
+}
+
+static int lg4573_disable(struct drm_panel *panel)
+{
+       struct lg4573 *ctx = panel_to_lg4573(panel);
+
+       return lg4573_display_off(ctx);
+}
+
+static int lg4573_enable(struct drm_panel *panel)
+{
+       struct lg4573 *ctx = panel_to_lg4573(panel);
+
+       lg4573_init(ctx);
+
+       return lg4573_power_on(ctx);
+}
+
+static const struct drm_display_mode default_mode = {
+       .clock = 27000,
+       .hdisplay = 480,
+       .hsync_start = 480 + 10,
+       .hsync_end = 480 + 10 + 59,
+       .htotal = 480 + 10 + 59 + 10,
+       .vdisplay = 800,
+       .vsync_start = 800 + 15,
+       .vsync_end = 800 + 15 + 15,
+       .vtotal = 800 + 15 + 15 + 15,
+       .vrefresh = 60,
+};
+
+static int lg4573_get_modes(struct drm_panel *panel)
+{
+       struct drm_connector *connector = panel->connector;
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_duplicate(panel->drm, &default_mode);
+       if (!mode) {
+               dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
+                       default_mode.hdisplay, default_mode.vdisplay,
+                       default_mode.vrefresh);
+               return -ENOMEM;
+       }
+
+       drm_mode_set_name(mode);
+
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+       drm_mode_probed_add(connector, mode);
+
+       panel->connector->display_info.width_mm = 61;
+       panel->connector->display_info.height_mm = 103;
+
+       return 1;
+}
+
+static const struct drm_panel_funcs lg4573_drm_funcs = {
+       .disable = lg4573_disable,
+       .enable = lg4573_enable,
+       .get_modes = lg4573_get_modes,
+};
+
+static int lg4573_probe(struct spi_device *spi)
+{
+       struct lg4573 *ctx;
+       int ret;
+
+       ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->spi = spi;
+
+       spi_set_drvdata(spi, ctx);
+       spi->bits_per_word = 8;
+
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               dev_err(&spi->dev, "SPI setup failed: %d\n", ret);
+               return ret;
+       }
+
+       drm_panel_init(&ctx->panel);
+       ctx->panel.dev = &spi->dev;
+       ctx->panel.funcs = &lg4573_drm_funcs;
+
+       return drm_panel_add(&ctx->panel);
+}
+
+static int lg4573_remove(struct spi_device *spi)
+{
+       struct lg4573 *ctx = spi_get_drvdata(spi);
+
+       lg4573_display_off(ctx);
+       drm_panel_remove(&ctx->panel);
+
+       return 0;
+}
+
+static const struct of_device_id lg4573_of_match[] = {
+       { .compatible = "lg,lg4573" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, lg4573_of_match);
+
+static struct spi_driver lg4573_driver = {
+       .probe = lg4573_probe,
+       .remove = lg4573_remove,
+       .driver = {
+               .name = "lg4573",
+               .owner = THIS_MODULE,
+               .of_match_table = lg4573_of_match,
+       },
+};
+module_spi_driver(lg4573_driver);
+
+MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
+MODULE_DESCRIPTION("lg4573 LCD Driver");
+MODULE_LICENSE("GPL v2");
similarity index 99%
rename from drivers/gpu/drm/panel/panel-ld9040.c
rename to drivers/gpu/drm/panel/panel-samsung-ld9040.c
index 9c27bded4c09a0afb1e7955da476f6c19b63bcfc..b202377135e7b320e825e6005bcb1d733fc1a47a 100644 (file)
@@ -377,7 +377,7 @@ static struct spi_driver ld9040_driver = {
        .probe = ld9040_probe,
        .remove = ld9040_remove,
        .driver = {
-               .name = "ld9040",
+               .name = "panel-samsung-ld9040",
                .owner = THIS_MODULE,
                .of_match_table = ld9040_of_match,
        },
similarity index 99%
rename from drivers/gpu/drm/panel/panel-s6e8aa0.c
rename to drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
index 30051108eec4869b7ec89d8d93ed4c4fe41662cf..a188a3959f1ad33384fb266b967853a61bb4f973 100644 (file)
@@ -1051,7 +1051,7 @@ static struct mipi_dsi_driver s6e8aa0_driver = {
        .probe = s6e8aa0_probe,
        .remove = s6e8aa0_remove,
        .driver = {
-               .name = "panel_s6e8aa0",
+               .name = "panel-samsung-s6e8aa0",
                .of_match_table = s6e8aa0_of_match,
        },
 };
index f94201b6e8821bd06fb53a0d437823e9f7ecc8b8..f97b73ec4713722ae3af5a05ba048ea95042e4e0 100644 (file)
@@ -713,7 +713,12 @@ static const struct display_timing hannstar_hsd070pww1_timing = {
        .hactive = { 1280, 1280, 1280 },
        .hfront_porch = { 1, 1, 10 },
        .hback_porch = { 1, 1, 10 },
-       .hsync_len = { 52, 158, 661 },
+       /*
+        * According to the data sheet, the minimum horizontal blanking interval
+        * is 54 clocks (1 + 52 + 1), but tests with a Nitrogen6X have shown the
+        * minimum working horizontal blanking interval to be 60 clocks.
+        */
+       .hsync_len = { 58, 158, 661 },
        .vactive = { 800, 800, 800 },
        .vfront_porch = { 1, 1, 10 },
        .vback_porch = { 1, 1, 10 },
@@ -729,6 +734,7 @@ static const struct panel_desc hannstar_hsd070pww1 = {
                .width = 151,
                .height = 94,
        },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
 };
 
 static const struct display_timing hannstar_hsd100pxn1_timing = {
@@ -943,6 +949,60 @@ static const struct panel_desc lg_lp129qe = {
        },
 };
 
+static const struct drm_display_mode nec_nl4827hc19_05b_mode = {
+       .clock = 10870,
+       .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 + 4,
+       .vtotal = 272 + 2 + 4 + 2,
+       .vrefresh = 74,
+};
+
+static const struct panel_desc nec_nl4827hc19_05b = {
+       .modes = &nec_nl4827hc19_05b_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 95,
+               .height = 54,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24
+};
+
+static const struct display_timing okaya_rs800480t_7x0gp_timing = {
+       .pixelclock = { 30000000, 30000000, 40000000 },
+       .hactive = { 800, 800, 800 },
+       .hfront_porch = { 40, 40, 40 },
+       .hback_porch = { 40, 40, 40 },
+       .hsync_len = { 1, 48, 48 },
+       .vactive = { 480, 480, 480 },
+       .vfront_porch = { 13, 13, 13 },
+       .vback_porch = { 29, 29, 29 },
+       .vsync_len = { 3, 3, 3 },
+       .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc okaya_rs800480t_7x0gp = {
+       .timings = &okaya_rs800480t_7x0gp_timing,
+       .num_timings = 1,
+       .bpc = 6,
+       .size = {
+               .width = 154,
+               .height = 87,
+       },
+       .delay = {
+               .prepare = 41,
+               .enable = 50,
+               .unprepare = 41,
+               .disable = 50,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
 static const struct drm_display_mode ortustech_com43h4m85ulc_mode  = {
        .clock = 25000,
        .hdisplay = 480,
@@ -1112,6 +1172,12 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "lg,lp129qe",
                .data = &lg_lp129qe,
+       }, {
+               .compatible = "nec,nl4827hc19-05b",
+               .data = &nec_nl4827hc19_05b,
+       }, {
+               .compatible = "okaya,rs800480t-7x0gp",
+               .data = &okaya_rs800480t_7x0gp,
        }, {
                .compatible = "ortustech,com43h4m85ulc",
                .data = &ortustech_com43h4m85ulc,
@@ -1169,6 +1235,34 @@ struct panel_desc_dsi {
        unsigned int lanes;
 };
 
+static const struct drm_display_mode auo_b080uan01_mode = {
+       .clock = 154500,
+       .hdisplay = 1200,
+       .hsync_start = 1200 + 62,
+       .hsync_end = 1200 + 62 + 4,
+       .htotal = 1200 + 62 + 4 + 62,
+       .vdisplay = 1920,
+       .vsync_start = 1920 + 9,
+       .vsync_end = 1920 + 9 + 2,
+       .vtotal = 1920 + 9 + 2 + 8,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc_dsi auo_b080uan01 = {
+       .desc = {
+               .modes = &auo_b080uan01_mode,
+               .num_modes = 1,
+               .bpc = 8,
+               .size = {
+                       .width = 108,
+                       .height = 272,
+               },
+       },
+       .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS,
+       .format = MIPI_DSI_FMT_RGB888,
+       .lanes = 4,
+};
+
 static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
        .clock = 71000,
        .hdisplay = 800,
@@ -1256,6 +1350,9 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
 
 static const struct of_device_id dsi_of_match[] = {
        {
+               .compatible = "auo,b080uan01",
+               .data = &auo_b080uan01
+       }, {
                .compatible = "lg,ld070wx3-sl01",
                .data = &lg_ld070wx3_sl01
        }, {
index 6b6e57e8c2d6292255d2cb1438f1ec36025511e4..41c422fee31a02dbc932964bc4686921e533fdd3 100644 (file)
@@ -197,7 +197,7 @@ static void qxl_fb_fillrect(struct fb_info *info,
 {
        struct qxl_fbdev *qfbdev = info->par;
 
-       sys_fillrect(info, rect);
+       drm_fb_helper_sys_fillrect(info, rect);
        qxl_dirty_update(qfbdev, rect->dx, rect->dy, rect->width,
                         rect->height);
 }
@@ -207,7 +207,7 @@ static void qxl_fb_copyarea(struct fb_info *info,
 {
        struct qxl_fbdev *qfbdev = info->par;
 
-       sys_copyarea(info, area);
+       drm_fb_helper_sys_copyarea(info, area);
        qxl_dirty_update(qfbdev, area->dx, area->dy, area->width,
                         area->height);
 }
@@ -217,7 +217,7 @@ static void qxl_fb_imageblit(struct fb_info *info,
 {
        struct qxl_fbdev *qfbdev = info->par;
 
-       sys_imageblit(info, image);
+       drm_fb_helper_sys_imageblit(info, image);
        qxl_dirty_update(qfbdev, image->dx, image->dy, image->width,
                         image->height);
 }
@@ -345,7 +345,6 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
        struct drm_mode_fb_cmd2 mode_cmd;
        struct drm_gem_object *gobj = NULL;
        struct qxl_bo *qbo = NULL;
-       struct device *device = &qdev->pdev->dev;
        int ret;
        int size;
        int bpp = sizes->surface_bpp;
@@ -374,9 +373,9 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
                 shadow);
        size = mode_cmd.pitches[0] * mode_cmd.height;
 
-       info = framebuffer_alloc(0, device);
-       if (info == NULL) {
-               ret = -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(&qfbdev->helper);
+       if (IS_ERR(info)) {
+               ret = PTR_ERR(info);
                goto out_unref;
        }
 
@@ -388,7 +387,7 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
 
        /* setup helper with fb data */
        qfbdev->helper.fb = fb;
-       qfbdev->helper.fbdev = info;
+
        qfbdev->shadow = shadow;
        strcpy(info->fix.id, "qxldrmfb");
 
@@ -410,11 +409,6 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
                               sizes->fb_height);
 
        /* setup aperture base/size for vesafb takeover */
-       info->apertures = alloc_apertures(1);
-       if (!info->apertures) {
-               ret = -ENOMEM;
-               goto out_unref;
-       }
        info->apertures->ranges[0].base = qdev->ddev->mode_config.fb_base;
        info->apertures->ranges[0].size = qdev->vram_size;
 
@@ -423,13 +417,7 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
 
        if (info->screen_base == NULL) {
                ret = -ENOSPC;
-               goto out_unref;
-       }
-
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto out_unref;
+               goto out_destroy_fbi;
        }
 
        info->fbdefio = &qxl_defio;
@@ -441,6 +429,8 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
        DRM_INFO("fb: depth %d, pitch %d, width %d, height %d\n", fb->depth, fb->pitches[0], fb->width, fb->height);
        return 0;
 
+out_destroy_fbi:
+       drm_fb_helper_release_fbi(&qfbdev->helper);
 out_unref:
        if (qbo) {
                ret = qxl_bo_reserve(qbo, false);
@@ -479,15 +469,11 @@ static int qxl_fb_find_or_create_single(
 
 static int qxl_fbdev_destroy(struct drm_device *dev, struct qxl_fbdev *qfbdev)
 {
-       struct fb_info *info;
        struct qxl_framebuffer *qfb = &qfbdev->qfb;
 
-       if (qfbdev->helper.fbdev) {
-               info = qfbdev->helper.fbdev;
+       drm_fb_helper_unregister_fbi(&qfbdev->helper);
+       drm_fb_helper_release_fbi(&qfbdev->helper);
 
-               unregister_framebuffer(info);
-               framebuffer_release(info);
-       }
        if (qfb->obj) {
                qxlfb_destroy_pinned_object(qfb->obj);
                qfb->obj = NULL;
@@ -557,7 +543,7 @@ void qxl_fbdev_fini(struct qxl_device *qdev)
 
 void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state)
 {
-       fb_set_suspend(qdev->mode_info.qfbdev->helper.fbdev, state);
+       drm_fb_helper_set_suspend(&qdev->mode_info.qfbdev->helper, state);
 }
 
 bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj)
index 6d6f33de48f48a93da1a0eadf681c5ac46874b4a..b28370e014c6c0b1547c5d88378d4d161e80a935 100644 (file)
@@ -272,7 +272,6 @@ void qxl_bo_force_delete(struct qxl_device *qdev)
                return;
        dev_err(qdev->dev, "Userspace still has active objects !\n");
        list_for_each_entry_safe(bo, n, &qdev->gem.objects, list) {
-               mutex_lock(&qdev->ddev->struct_mutex);
                dev_err(qdev->dev, "%p %p %lu %lu force free\n",
                        &bo->gem_base, bo, (unsigned long)bo->gem_base.size,
                        *((unsigned long *)&bo->gem_base.refcount));
@@ -280,8 +279,7 @@ void qxl_bo_force_delete(struct qxl_device *qdev)
                list_del_init(&bo->list);
                mutex_unlock(&qdev->gem.mutex);
                /* this should unref the ttm bo */
-               drm_gem_object_unreference(&bo->gem_base);
-               mutex_unlock(&qdev->ddev->struct_mutex);
+               drm_gem_object_unreference_unlocked(&bo->gem_base);
        }
 }
 
index dd39f434b4a7eccf1446ff5cd1857a2cf5de972d..c3872598b85a3856787b1bf0b7113633a468e020 100644 (file)
@@ -2299,8 +2299,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        encoder_mode = atombios_get_encoder_mode(encoder);
        if (connector && (radeon_audio != 0) &&
            ((encoder_mode == ATOM_ENCODER_MODE_HDMI) ||
-            (ENCODER_MODE_IS_DP(encoder_mode) &&
-             drm_detect_monitor_audio(radeon_connector_edid(connector)))))
+            ENCODER_MODE_IS_DP(encoder_mode)))
                radeon_audio_mode_set(encoder, adjusted_mode);
 }
 
index 68fd9fc677e35f1ca161295694301ec21c089e4d..44480c1b9738cc2625cee481ccf02aa20ed6bb1f 100644 (file)
@@ -93,30 +93,26 @@ void dce6_afmt_select_pin(struct drm_encoder *encoder)
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       u32 offset;
 
-       if (!dig || !dig->afmt || !dig->afmt->pin)
+       if (!dig || !dig->afmt || !dig->pin)
                return;
 
-       offset = dig->afmt->offset;
-
-       WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
-              AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));
+       WREG32(AFMT_AUDIO_SRC_CONTROL +  dig->afmt->offset,
+              AFMT_AUDIO_SRC_SELECT(dig->pin->id));
 }
 
 void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
-               struct drm_connector *connector, struct drm_display_mode *mode)
+                                   struct drm_connector *connector,
+                                   struct drm_display_mode *mode)
 {
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       u32 tmp = 0, offset;
+       u32 tmp = 0;
 
-       if (!dig || !dig->afmt || !dig->afmt->pin)
+       if (!dig || !dig->afmt || !dig->pin)
                return;
 
-       offset = dig->afmt->pin->offset;
-
        if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
                if (connector->latency_present[1])
                        tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
@@ -130,24 +126,24 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
                else
                        tmp = VIDEO_LIPSYNC(0) | AUDIO_LIPSYNC(0);
        }
-       WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
+       WREG32_ENDPOINT(dig->pin->offset,
+                       AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
 }
 
 void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
-       u8 *sadb, int sad_count)
+                                            u8 *sadb, int sad_count)
 {
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       u32 offset, tmp;
+       u32 tmp;
 
-       if (!dig || !dig->afmt || !dig->afmt->pin)
+       if (!dig || !dig->afmt || !dig->pin)
                return;
 
-       offset = dig->afmt->pin->offset;
-
        /* program the speaker allocation */
-       tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
+       tmp = RREG32_ENDPOINT(dig->pin->offset,
+                             AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
        tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
        /* set HDMI mode */
        tmp |= HDMI_CONNECTION;
@@ -155,24 +151,24 @@ void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
                tmp |= SPEAKER_ALLOCATION(sadb[0]);
        else
                tmp |= SPEAKER_ALLOCATION(5); /* stereo */
-       WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
+       WREG32_ENDPOINT(dig->pin->offset,
+                       AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
 }
 
 void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
-       u8 *sadb, int sad_count)
+                                          u8 *sadb, int sad_count)
 {
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       u32 offset, tmp;
+       u32 tmp;
 
-       if (!dig || !dig->afmt || !dig->afmt->pin)
+       if (!dig || !dig->afmt || !dig->pin)
                return;
 
-       offset = dig->afmt->pin->offset;
-
        /* program the speaker allocation */
-       tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
+       tmp = RREG32_ENDPOINT(dig->pin->offset,
+                             AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
        tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
        /* set DP mode */
        tmp |= DP_CONNECTION;
@@ -180,13 +176,13 @@ void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
                tmp |= SPEAKER_ALLOCATION(sadb[0]);
        else
                tmp |= SPEAKER_ALLOCATION(5); /* stereo */
-       WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
+       WREG32_ENDPOINT(dig->pin->offset,
+                       AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
 }
 
 void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
-       struct cea_sad *sads, int sad_count)
+                             struct cea_sad *sads, int sad_count)
 {
-       u32 offset;
        int i;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
@@ -206,11 +202,9 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
                { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
        };
 
-       if (!dig || !dig->afmt || !dig->afmt->pin)
+       if (!dig || !dig->afmt || !dig->pin)
                return;
 
-       offset = dig->afmt->pin->offset;
-
        for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
                u32 value = 0;
                u8 stereo_freqs = 0;
@@ -237,7 +231,7 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
 
                value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
 
-               WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);
+               WREG32_ENDPOINT(dig->pin->offset, eld_reg_to_type[i][0], value);
        }
 }
 
@@ -253,7 +247,7 @@ void dce6_audio_enable(struct radeon_device *rdev,
 }
 
 void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
-       struct radeon_crtc *crtc, unsigned int clock)
+                            struct radeon_crtc *crtc, unsigned int clock)
 {
        /* Two dtos; generally use dto0 for HDMI */
        u32 value = 0;
@@ -272,7 +266,7 @@ void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
 }
 
 void dce6_dp_audio_set_dto(struct radeon_device *rdev,
-       struct radeon_crtc *crtc, unsigned int clock)
+                          struct radeon_crtc *crtc, unsigned int clock)
 {
        /* Two dtos; generally use dto1 for DP */
        u32 value = 0;
index fa719c53449bcd90e009e1b59d1b3e1ed5bff6f3..fbc8d88d6e5de1afe43c11884340e90bfa8e57a2 100644 (file)
@@ -245,6 +245,28 @@ static struct radeon_audio_funcs dce6_dp_funcs = {
 static void radeon_audio_enable(struct radeon_device *rdev,
                                struct r600_audio_pin *pin, u8 enable_mask)
 {
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
+       struct radeon_encoder_atom_dig *dig;
+       int pin_count = 0;
+
+       if (!pin)
+               return;
+
+       if (rdev->mode_info.mode_config_initialized) {
+               list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) {
+                       if (radeon_encoder_is_digital(encoder)) {
+                               radeon_encoder = to_radeon_encoder(encoder);
+                               dig = radeon_encoder->enc_priv;
+                               if (dig->pin == pin)
+                                       pin_count++;
+                       }
+               }
+
+               if ((pin_count > 1) && (enable_mask == 0))
+                       return;
+       }
+
        if (rdev->audio.funcs->enable)
                rdev->audio.funcs->enable(rdev, pin, enable_mask);
 }
@@ -336,24 +358,13 @@ void radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset,
 
 static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
 {
-       struct radeon_encoder *radeon_encoder;
-       struct drm_connector *connector;
-       struct radeon_connector *radeon_connector = NULL;
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct cea_sad *sads;
        int sad_count;
 
-       list_for_each_entry(connector,
-               &encoder->dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       radeon_connector = to_radeon_connector(connector);
-                       break;
-               }
-       }
-
-       if (!radeon_connector) {
-               DRM_ERROR("Couldn't find encoder's connector\n");
+       if (!connector)
                return;
-       }
 
        sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
        if (sad_count <= 0) {
@@ -362,8 +373,6 @@ static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
        }
        BUG_ON(!sads);
 
-       radeon_encoder = to_radeon_encoder(encoder);
-
        if (radeon_encoder->audio && radeon_encoder->audio->write_sad_regs)
                radeon_encoder->audio->write_sad_regs(encoder, sads, sad_count);
 
@@ -372,27 +381,16 @@ static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
 
 static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
 {
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       struct drm_connector *connector;
-       struct radeon_connector *radeon_connector = NULL;
        u8 *sadb = NULL;
        int sad_count;
 
-       list_for_each_entry(connector,
-                           &encoder->dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       radeon_connector = to_radeon_connector(connector);
-                       break;
-               }
-       }
-
-       if (!radeon_connector) {
-               DRM_ERROR("Couldn't find encoder's connector\n");
+       if (!connector)
                return;
-       }
 
-       sad_count = drm_edid_to_speaker_allocation(
-               radeon_connector_edid(connector), &sadb);
+       sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector),
+                                                  &sadb);
        if (sad_count < 0) {
                DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n",
                          sad_count);
@@ -406,26 +404,13 @@ static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
 }
 
 static void radeon_audio_write_latency_fields(struct drm_encoder *encoder,
-       struct drm_display_mode *mode)
+                                             struct drm_display_mode *mode)
 {
-       struct radeon_encoder *radeon_encoder;
-       struct drm_connector *connector;
-       struct radeon_connector *radeon_connector = 0;
-
-       list_for_each_entry(connector,
-               &encoder->dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       radeon_connector = to_radeon_connector(connector);
-                       break;
-               }
-       }
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 
-       if (!radeon_connector) {
-               DRM_ERROR("Couldn't find encoder's connector\n");
+       if (!connector)
                return;
-       }
-
-       radeon_encoder = to_radeon_encoder(encoder);
 
        if (radeon_encoder->audio && radeon_encoder->audio->write_latency_fields)
                radeon_encoder->audio->write_latency_fields(encoder, connector, mode);
@@ -451,29 +436,23 @@ static void radeon_audio_select_pin(struct drm_encoder *encoder)
 }
 
 void radeon_audio_detect(struct drm_connector *connector,
+                        struct drm_encoder *encoder,
                         enum drm_connector_status status)
 {
-       struct radeon_device *rdev;
-       struct radeon_encoder *radeon_encoder;
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig;
 
-       if (!connector || !connector->encoder)
+       if (!radeon_audio_chipset_supported(rdev))
                return;
 
-       rdev = connector->encoder->dev->dev_private;
-
-       if (!radeon_audio_chipset_supported(rdev))
+       if (!radeon_encoder_is_digital(encoder))
                return;
 
-       radeon_encoder = to_radeon_encoder(connector->encoder);
        dig = radeon_encoder->enc_priv;
 
        if (status == connector_status_connected) {
-               if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) {
-                       radeon_encoder->audio = NULL;
-                       return;
-               }
-
                if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
                        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 
@@ -486,11 +465,17 @@ void radeon_audio_detect(struct drm_connector *connector,
                        radeon_encoder->audio = rdev->audio.hdmi_funcs;
                }
 
-               dig->afmt->pin = radeon_audio_get_pin(connector->encoder);
-               radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+               if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
+                       if (!dig->pin)
+                               dig->pin = radeon_audio_get_pin(encoder);
+                       radeon_audio_enable(rdev, dig->pin, 0xf);
+               } else {
+                       radeon_audio_enable(rdev, dig->pin, 0);
+                       dig->pin = NULL;
+               }
        } else {
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
-               dig->afmt->pin = NULL;
+               radeon_audio_enable(rdev, dig->pin, 0);
+               dig->pin = NULL;
        }
 }
 
@@ -518,29 +503,18 @@ static void radeon_audio_set_dto(struct drm_encoder *encoder, unsigned int clock
 }
 
 static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
-       struct drm_display_mode *mode)
+                                      struct drm_display_mode *mode)
 {
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       struct drm_connector *connector;
-       struct radeon_connector *radeon_connector = NULL;
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
        struct hdmi_avi_infoframe frame;
        int err;
 
-       list_for_each_entry(connector,
-               &encoder->dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       radeon_connector = to_radeon_connector(connector);
-                       break;
-               }
-       }
-
-       if (!radeon_connector) {
-               DRM_ERROR("Couldn't find encoder's connector\n");
-               return -ENOENT;
-       }
+       if (!connector)
+               return -EINVAL;
 
        err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
        if (err < 0) {
@@ -563,8 +537,8 @@ static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
                return err;
        }
 
-       if (dig && dig->afmt &&
-               radeon_encoder->audio && radeon_encoder->audio->set_avi_packet)
+       if (dig && dig->afmt && radeon_encoder->audio &&
+           radeon_encoder->audio->set_avi_packet)
                radeon_encoder->audio->set_avi_packet(rdev, dig->afmt->offset,
                        buffer, sizeof(buffer));
 
@@ -722,30 +696,41 @@ static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
        if (!dig || !dig->afmt)
                return;
 
-       radeon_audio_set_mute(encoder, true);
+       if (!connector)
+               return;
 
-       radeon_audio_write_speaker_allocation(encoder);
-       radeon_audio_write_sad_regs(encoder);
-       radeon_audio_write_latency_fields(encoder, mode);
-       radeon_audio_set_dto(encoder, mode->clock);
-       radeon_audio_set_vbi_packet(encoder);
-       radeon_hdmi_set_color_depth(encoder);
-       radeon_audio_update_acr(encoder, mode->clock);
-       radeon_audio_set_audio_packet(encoder);
-       radeon_audio_select_pin(encoder);
+       if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
+               radeon_audio_set_mute(encoder, true);
 
-       if (radeon_audio_set_avi_packet(encoder, mode) < 0)
-               return;
+               radeon_audio_write_speaker_allocation(encoder);
+               radeon_audio_write_sad_regs(encoder);
+               radeon_audio_write_latency_fields(encoder, mode);
+               radeon_audio_set_dto(encoder, mode->clock);
+               radeon_audio_set_vbi_packet(encoder);
+               radeon_hdmi_set_color_depth(encoder);
+               radeon_audio_update_acr(encoder, mode->clock);
+               radeon_audio_set_audio_packet(encoder);
+               radeon_audio_select_pin(encoder);
+
+               if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+                       return;
 
-       radeon_audio_set_mute(encoder, false);
+               radeon_audio_set_mute(encoder, false);
+       } else {
+               radeon_hdmi_set_color_depth(encoder);
+
+               if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+                       return;
+       }
 }
 
 static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
-       struct drm_display_mode *mode)
+                                    struct drm_display_mode *mode)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -759,22 +744,27 @@ static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
        if (!dig || !dig->afmt)
                return;
 
-       radeon_audio_write_speaker_allocation(encoder);
-       radeon_audio_write_sad_regs(encoder);
-       radeon_audio_write_latency_fields(encoder, mode);
-       if (rdev->clock.dp_extclk || ASIC_IS_DCE5(rdev))
-               radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
-       else
-               radeon_audio_set_dto(encoder, dig_connector->dp_clock);
-       radeon_audio_set_audio_packet(encoder);
-       radeon_audio_select_pin(encoder);
-
-       if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+       if (!connector)
                return;
+
+       if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
+               radeon_audio_write_speaker_allocation(encoder);
+               radeon_audio_write_sad_regs(encoder);
+               radeon_audio_write_latency_fields(encoder, mode);
+               if (rdev->clock.dp_extclk || ASIC_IS_DCE5(rdev))
+                       radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
+               else
+                       radeon_audio_set_dto(encoder, dig_connector->dp_clock);
+               radeon_audio_set_audio_packet(encoder);
+               radeon_audio_select_pin(encoder);
+
+               if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+                       return;
+       }
 }
 
 void radeon_audio_mode_set(struct drm_encoder *encoder,
-       struct drm_display_mode *mode)
+                          struct drm_display_mode *mode)
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 
index 8438304f7139549c9ab785ec3f1decd50ac3254a..059cc3012062a7b50708620c557771dcfea821c0 100644 (file)
@@ -68,7 +68,8 @@ struct radeon_audio_funcs
 
 int radeon_audio_init(struct radeon_device *rdev);
 void radeon_audio_detect(struct drm_connector *connector,
-       enum drm_connector_status status);
+                        struct drm_encoder *encoder,
+                        enum drm_connector_status status);
 u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev,
        u32 offset, u32 reg);
 void radeon_audio_endpoint_wreg(struct radeon_device *rdev,
index 3e5f6b71f3adad72b0aae490ede2ae1f426c9ff5..c097d3a82bda734888ca46d05c14794738163642 100644 (file)
@@ -1255,10 +1255,15 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
 
                        if ((RBIOS16(tmp) == lvds->native_mode.hdisplay) &&
                            (RBIOS16(tmp + 2) == lvds->native_mode.vdisplay)) {
+                               u32 hss = (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - 1) * 8;
+
+                               if (hss > lvds->native_mode.hdisplay)
+                                       hss = (10 - 1) * 8;
+
                                lvds->native_mode.htotal = lvds->native_mode.hdisplay +
                                        (RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8;
                                lvds->native_mode.hsync_start = lvds->native_mode.hdisplay +
-                                       (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - 1) * 8;
+                                       hss;
                                lvds->native_mode.hsync_end = lvds->native_mode.hsync_start +
                                        (RBIOS8(tmp + 23) * 8);
 
index cebb65e07e1d13f0bee01ee753f4c8a76e0e22d5..94b21ae70ef725781c8dc7d0ec8a30fbd48f0e0e 100644 (file)
@@ -1379,8 +1379,16 @@ out:
        /* updated in get modes as well since we need to know if it's analog or digital */
        radeon_connector_update_scratch_regs(connector, ret);
 
-       if (radeon_audio != 0)
-               radeon_audio_detect(connector, ret);
+       if ((radeon_audio != 0) && radeon_connector->use_digital) {
+               const struct drm_connector_helper_funcs *connector_funcs =
+                       connector->helper_private;
+
+               encoder = connector_funcs->best_encoder(connector);
+               if (encoder && (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)) {
+                       radeon_connector_get_edid(connector);
+                       radeon_audio_detect(connector, encoder, ret);
+               }
+       }
 
 exit:
        pm_runtime_mark_last_busy(connector->dev->dev);
@@ -1717,8 +1725,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
 
        radeon_connector_update_scratch_regs(connector, ret);
 
-       if (radeon_audio != 0)
-               radeon_audio_detect(connector, ret);
+       if ((radeon_audio != 0) && encoder) {
+               radeon_connector_get_edid(connector);
+               radeon_audio_detect(connector, encoder, ret);
+       }
 
 out:
        pm_runtime_mark_last_busy(connector->dev->dev);
index e4fc8f3bf58b09175c0d1dc868b2ce52327c4c18..5e09c061847f50c688650d12625a462e8c4737cd 100644 (file)
@@ -246,9 +246,10 @@ radeon_dp_mst_connector_destroy(struct drm_connector *connector)
        kfree(radeon_connector);
 }
 
-static void radeon_connector_dpms(struct drm_connector *connector, int mode)
+static int radeon_connector_dpms(struct drm_connector *connector, int mode)
 {
        DRM_DEBUG_KMS("\n");
+       return 0;
 }
 
 static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = {
index aeb676708e60cfb1871326bfc5a689631bb98741..7214858ffceaa8c20409206533dcc332fd663705 100644 (file)
@@ -82,9 +82,9 @@ static struct fb_ops radeonfb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = radeon_fb_helper_set_par,
-       .fb_fillrect = cfb_fillrect,
-       .fb_copyarea = cfb_copyarea,
-       .fb_imageblit = cfb_imageblit,
+       .fb_fillrect = drm_fb_helper_cfb_fillrect,
+       .fb_copyarea = drm_fb_helper_cfb_copyarea,
+       .fb_imageblit = drm_fb_helper_cfb_imageblit,
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
@@ -227,7 +227,6 @@ static int radeonfb_create(struct drm_fb_helper *helper,
        struct drm_mode_fb_cmd2 mode_cmd;
        struct drm_gem_object *gobj = NULL;
        struct radeon_bo *rbo = NULL;
-       struct device *device = &rdev->pdev->dev;
        int ret;
        unsigned long tmp;
 
@@ -250,9 +249,9 @@ static int radeonfb_create(struct drm_fb_helper *helper,
        rbo = gem_to_radeon_bo(gobj);
 
        /* okay we have an object now allocate the framebuffer */
-       info = framebuffer_alloc(0, device);
-       if (info == NULL) {
-               ret = -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info)) {
+               ret = PTR_ERR(info);
                goto out_unref;
        }
 
@@ -262,14 +261,13 @@ static int radeonfb_create(struct drm_fb_helper *helper,
        ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
        if (ret) {
                DRM_ERROR("failed to initialize framebuffer %d\n", ret);
-               goto out_unref;
+               goto out_destroy_fbi;
        }
 
        fb = &rfbdev->rfb.base;
 
        /* setup helper */
        rfbdev->helper.fb = fb;
-       rfbdev->helper.fbdev = info;
 
        memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo));
 
@@ -289,11 +287,6 @@ static int radeonfb_create(struct drm_fb_helper *helper,
        drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
 
        /* setup aperture base/size for vesafb takeover */
-       info->apertures = alloc_apertures(1);
-       if (!info->apertures) {
-               ret = -ENOMEM;
-               goto out_unref;
-       }
        info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base;
        info->apertures->ranges[0].size = rdev->mc.aper_size;
 
@@ -301,13 +294,7 @@ static int radeonfb_create(struct drm_fb_helper *helper,
 
        if (info->screen_base == NULL) {
                ret = -ENOSPC;
-               goto out_unref;
-       }
-
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto out_unref;
+               goto out_destroy_fbi;
        }
 
        DRM_INFO("fb mappable at 0x%lX\n",  info->fix.smem_start);
@@ -319,6 +306,8 @@ static int radeonfb_create(struct drm_fb_helper *helper,
        vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
        return 0;
 
+out_destroy_fbi:
+       drm_fb_helper_release_fbi(helper);
 out_unref:
        if (rbo) {
 
@@ -339,17 +328,10 @@ void radeon_fb_output_poll_changed(struct radeon_device *rdev)
 
 static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
 {
-       struct fb_info *info;
        struct radeon_framebuffer *rfb = &rfbdev->rfb;
 
-       if (rfbdev->helper.fbdev) {
-               info = rfbdev->helper.fbdev;
-
-               unregister_framebuffer(info);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&rfbdev->helper);
+       drm_fb_helper_release_fbi(&rfbdev->helper);
 
        if (rfb->obj) {
                radeonfb_destroy_pinned_object(rfb->obj);
index 07909d817381a21a18fdeb5dd7cd8b4be92fbc8e..aecc3e3dec0ca093441e3871df414627b51e92ec 100644 (file)
@@ -237,7 +237,6 @@ struct radeon_afmt {
        int offset;
        bool last_buffer_filled_status;
        int id;
-       struct r600_audio_pin *pin;
 };
 
 struct radeon_mode_info {
@@ -439,6 +438,7 @@ struct radeon_encoder_atom_dig {
        uint8_t backlight_level;
        int panel_mode;
        struct radeon_afmt *afmt;
+       struct r600_audio_pin *pin;
        int active_mst_links;
 };
 
index 65d6ba6621aca5b1883ac8a4a57a93a92e0ca913..48cb19949ca3f01eeb365b3a1dadc30509888cfd 100644 (file)
@@ -496,7 +496,8 @@ static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc,
        return true;
 }
 
-static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc)
+static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc,
+                                     struct drm_crtc_state *old_crtc_state)
 {
        struct drm_pending_vblank_event *event = crtc->state->event;
        struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
@@ -512,7 +513,8 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc)
        }
 }
 
-static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc)
+static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc,
+                                     struct drm_crtc_state *old_crtc_state)
 {
        struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
 
index 5b0dc0f6fd940f7d6689f832e03c0c3cd1048656..f261512bb4a03539f55e40b0e545c3ee8469c57e 100644 (file)
@@ -37,9 +37,9 @@ static int rockchip_fbdev_mmap(struct fb_info *info,
 static struct fb_ops rockchip_drm_fbdev_ops = {
        .owner          = THIS_MODULE,
        .fb_mmap        = rockchip_fbdev_mmap,
-       .fb_fillrect    = cfb_fillrect,
-       .fb_copyarea    = cfb_copyarea,
-       .fb_imageblit   = cfb_imageblit,
+       .fb_fillrect    = drm_fb_helper_cfb_fillrect,
+       .fb_copyarea    = drm_fb_helper_cfb_copyarea,
+       .fb_imageblit   = drm_fb_helper_cfb_imageblit,
        .fb_check_var   = drm_fb_helper_check_var,
        .fb_set_par     = drm_fb_helper_set_par,
        .fb_blank       = drm_fb_helper_blank,
@@ -77,10 +77,10 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
 
        private->fbdev_bo = &rk_obj->base;
 
-       fbi = framebuffer_alloc(0, dev->dev);
-       if (!fbi) {
-               dev_err(dev->dev, "Failed to allocate framebuffer info.\n");
-               ret = -ENOMEM;
+       fbi = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(fbi)) {
+               dev_err(dev->dev, "Failed to create framebuffer info.\n");
+               ret = PTR_ERR(fbi);
                goto err_rockchip_gem_free_object;
        }
 
@@ -89,21 +89,13 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
        if (IS_ERR(helper->fb)) {
                dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
                ret = PTR_ERR(helper->fb);
-               goto err_framebuffer_release;
+               goto err_release_fbi;
        }
 
-       helper->fbdev = fbi;
-
        fbi->par = helper;
        fbi->flags = FBINFO_FLAG_DEFAULT;
        fbi->fbops = &rockchip_drm_fbdev_ops;
 
-       ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
-       if (ret) {
-               dev_err(dev->dev, "Failed to allocate color map.\n");
-               goto err_drm_framebuffer_unref;
-       }
-
        fb = helper->fb;
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
        drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
@@ -124,10 +116,8 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
 
        return 0;
 
-err_drm_framebuffer_unref:
-       drm_framebuffer_unreference(helper->fb);
-err_framebuffer_release:
-       framebuffer_release(fbi);
+err_release_fbi:
+       drm_fb_helper_release_fbi(helper);
 err_rockchip_gem_free_object:
        rockchip_gem_free_object(&rk_obj->base);
        return ret;
@@ -190,21 +180,8 @@ void rockchip_drm_fbdev_fini(struct drm_device *dev)
 
        helper = &private->fbdev_helper;
 
-       if (helper->fbdev) {
-               struct fb_info *info;
-               int ret;
-
-               info = helper->fbdev;
-               ret = unregister_framebuffer(info);
-               if (ret < 0)
-                       DRM_DEBUG_KMS("failed unregister_framebuffer() - %d\n",
-                                     ret);
-
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(helper);
+       drm_fb_helper_release_fbi(helper);
 
        if (helper->fb)
                drm_framebuffer_unreference(helper->fb);
index eba5f8a52fbd9ff2bf7941687f54e11320cb10b3..a6d9104f7f157f55426843690dee62c00e97cb4b 100644 (file)
@@ -200,13 +200,10 @@ int rockchip_gem_dumb_map_offset(struct drm_file *file_priv,
        struct drm_gem_object *obj;
        int ret;
 
-       mutex_lock(&dev->struct_mutex);
-
        obj = drm_gem_object_lookup(dev, file_priv, handle);
        if (!obj) {
                DRM_ERROR("failed to lookup gem object.\n");
-               ret = -EINVAL;
-               goto unlock;
+               return -EINVAL;
        }
 
        ret = drm_gem_create_mmap_offset(obj);
@@ -217,10 +214,9 @@ int rockchip_gem_dumb_map_offset(struct drm_file *file_priv,
        DRM_DEBUG_KMS("offset = 0x%llx\n", *offset);
 
 out:
-       drm_gem_object_unreference(obj);
-unlock:
-       mutex_unlock(&dev->struct_mutex);
-       return ret;
+       drm_gem_object_unreference_unlocked(obj);
+
+       return 0;
 }
 
 /*
index f0f1e4ee2d922060d579e40ed2f664576f94a1d5..e27490b492a5280a254b9a196d452f429abb9466 100644 (file)
@@ -1,12 +1,11 @@
 sticompositor-y := \
-       sti_layer.o \
        sti_mixer.o \
        sti_gdp.o \
        sti_vid.o \
        sti_cursor.o \
        sti_compositor.o \
-       sti_drm_crtc.o \
-       sti_drm_plane.o
+       sti_crtc.o \
+       sti_plane.o
 
 stihdmi-y := sti_hdmi.o \
        sti_hdmi_tx3g0c55phy.o \
@@ -24,4 +23,4 @@ obj-$(CONFIG_DRM_STI) = \
        sticompositor.o \
        sti_hqvdp.o \
        stidvo.o \
-       sti_drm_drv.o
+       sti_drv.o
index 43215d3020fb6e8060d2fd2fb48e0e50b3c28c47..c652627b1bcadbe05a1a759677724f7be8819c0a 100644 (file)
 #include <drm/drmP.h>
 
 #include "sti_compositor.h"
-#include "sti_drm_crtc.h"
-#include "sti_drm_drv.h"
-#include "sti_drm_plane.h"
+#include "sti_crtc.h"
+#include "sti_cursor.h"
+#include "sti_drv.h"
 #include "sti_gdp.h"
+#include "sti_plane.h"
+#include "sti_vid.h"
 #include "sti_vtg.h"
 
 /*
@@ -31,7 +33,7 @@ struct sti_compositor_data stih407_compositor_data = {
                        {STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200},
                        {STI_GPD_SUBDEV, (int)STI_GDP_2, 0x300},
                        {STI_GPD_SUBDEV, (int)STI_GDP_3, 0x400},
-                       {STI_VID_SUBDEV, (int)STI_VID_0, 0x700},
+                       {STI_VID_SUBDEV, (int)STI_HQVDP_0, 0x700},
                        {STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00},
                        {STI_MIXER_AUX_SUBDEV, STI_MIXER_AUX, 0xD00},
        },
@@ -53,14 +55,29 @@ struct sti_compositor_data stih416_compositor_data = {
        },
 };
 
-static int sti_compositor_init_subdev(struct sti_compositor *compo,
-               struct sti_compositor_subdev_descriptor *desc,
-               unsigned int array_size)
+static int sti_compositor_bind(struct device *dev,
+                              struct device *master,
+                              void *data)
 {
-       unsigned int i, mixer_id = 0, layer_id = 0;
+       struct sti_compositor *compo = dev_get_drvdata(dev);
+       struct drm_device *drm_dev = data;
+       unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0;
+       struct sti_private *dev_priv = drm_dev->dev_private;
+       struct drm_plane *cursor = NULL;
+       struct drm_plane *primary = NULL;
+       struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc;
+       unsigned int array_size = compo->data.nb_subdev;
+
+       dev_priv->compo = compo;
 
+       /* Register mixer subdev and video subdev first */
        for (i = 0; i < array_size; i++) {
                switch (desc[i].type) {
+               case STI_VID_SUBDEV:
+                       compo->vid[vid_id++] =
+                           sti_vid_create(compo->dev, desc[i].id,
+                                          compo->regs + desc[i].offset);
+                       break;
                case STI_MIXER_MAIN_SUBDEV:
                case STI_MIXER_AUX_SUBDEV:
                        compo->mixer[mixer_id++] =
@@ -68,83 +85,68 @@ static int sti_compositor_init_subdev(struct sti_compositor *compo,
                                             compo->regs + desc[i].offset);
                        break;
                case STI_GPD_SUBDEV:
-               case STI_VID_SUBDEV:
                case STI_CURSOR_SUBDEV:
-                       compo->layer[layer_id++] =
-                           sti_layer_create(compo->dev, desc[i].id,
-                                            compo->regs + desc[i].offset);
+                       /* Nothing to do, wait for the second round */
                        break;
                default:
                        DRM_ERROR("Unknow subdev compoment type\n");
                        return 1;
                }
-
        }
-       compo->nb_mixers = mixer_id;
-       compo->nb_layers = layer_id;
-
-       return 0;
-}
-
-static int sti_compositor_bind(struct device *dev, struct device *master,
-       void *data)
-{
-       struct sti_compositor *compo = dev_get_drvdata(dev);
-       struct drm_device *drm_dev = data;
-       unsigned int i, crtc = 0, plane = 0;
-       struct sti_drm_private *dev_priv = drm_dev->dev_private;
-       struct drm_plane *cursor = NULL;
-       struct drm_plane *primary = NULL;
 
-       dev_priv->compo = compo;
-
-       for (i = 0; i < compo->nb_layers; i++) {
-               if (compo->layer[i]) {
-                       enum sti_layer_desc desc = compo->layer[i]->desc;
-                       enum sti_layer_type type = desc & STI_LAYER_TYPE_MASK;
-                       enum drm_plane_type plane_type = DRM_PLANE_TYPE_OVERLAY;
+       /* Register the other subdevs, create crtc and planes */
+       for (i = 0; i < array_size; i++) {
+               enum drm_plane_type plane_type = DRM_PLANE_TYPE_OVERLAY;
 
-                       if (crtc < compo->nb_mixers)
-                               plane_type = DRM_PLANE_TYPE_PRIMARY;
+               if (crtc_id < mixer_id)
+                       plane_type = DRM_PLANE_TYPE_PRIMARY;
 
-                       switch (type) {
-                       case STI_CUR:
-                               cursor = sti_drm_plane_init(drm_dev,
-                                               compo->layer[i],
-                                               1, DRM_PLANE_TYPE_CURSOR);
-                               break;
-                       case STI_GDP:
-                       case STI_VID:
-                               primary = sti_drm_plane_init(drm_dev,
-                                               compo->layer[i],
-                                               (1 << compo->nb_mixers) - 1,
-                                               plane_type);
-                               plane++;
+               switch (desc[i].type) {
+               case STI_MIXER_MAIN_SUBDEV:
+               case STI_MIXER_AUX_SUBDEV:
+               case STI_VID_SUBDEV:
+                       /* Nothing to do, already done at the first round */
+                       break;
+               case STI_CURSOR_SUBDEV:
+                       cursor = sti_cursor_create(drm_dev, compo->dev,
+                                                  desc[i].id,
+                                                  compo->regs + desc[i].offset,
+                                                  1);
+                       if (!cursor) {
+                               DRM_ERROR("Can't create CURSOR plane\n");
                                break;
-                       case STI_BCK:
-                       case STI_VDP:
+                       }
+                       break;
+               case STI_GPD_SUBDEV:
+                       primary = sti_gdp_create(drm_dev, compo->dev,
+                                                desc[i].id,
+                                                compo->regs + desc[i].offset,
+                                                (1 << mixer_id) - 1,
+                                                plane_type);
+                       if (!primary) {
+                               DRM_ERROR("Can't create GDP plane\n");
                                break;
                        }
+                       break;
+               default:
+                       DRM_ERROR("Unknown subdev compoment type\n");
+                       return 1;
+               }
 
-                       /* The first planes are reserved for primary planes*/
-                       if (crtc < compo->nb_mixers && primary) {
-                               sti_drm_crtc_init(drm_dev, compo->mixer[crtc],
-                                               primary, cursor);
-                               crtc++;
-                               cursor = NULL;
-                               primary = NULL;
-                       }
+               /* The first planes are reserved for primary planes*/
+               if (crtc_id < mixer_id && primary) {
+                       sti_crtc_init(drm_dev, compo->mixer[crtc_id],
+                                     primary, cursor);
+                       crtc_id++;
+                       cursor = NULL;
+                       primary = NULL;
                }
        }
 
-       drm_vblank_init(drm_dev, crtc);
+       drm_vblank_init(drm_dev, crtc_id);
        /* Allow usage of vblank without having to call drm_irq_install */
        drm_dev->irq_enabled = 1;
 
-       DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n",
-                        crtc, plane);
-       DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n");
-
        return 0;
 }
 
@@ -179,7 +181,6 @@ static int sti_compositor_probe(struct platform_device *pdev)
        struct device_node *vtg_np;
        struct sti_compositor *compo;
        struct resource *res;
-       int err;
 
        compo = devm_kzalloc(dev, sizeof(*compo), GFP_KERNEL);
        if (!compo) {
@@ -187,7 +188,7 @@ static int sti_compositor_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
        compo->dev = dev;
-       compo->vtg_vblank_nb.notifier_call = sti_drm_crtc_vblank_cb;
+       compo->vtg_vblank_nb.notifier_call = sti_crtc_vblank_cb;
 
        /* populate data structure depending on compatibility */
        BUG_ON(!of_match_node(compositor_of_match, np)->data);
@@ -251,12 +252,6 @@ static int sti_compositor_probe(struct platform_device *pdev)
        if (vtg_np)
                compo->vtg_aux = of_vtg_find(vtg_np);
 
-       /* Initialize compositor subdevices */
-       err = sti_compositor_init_subdev(compo, compo->data.subdev_desc,
-                                        compo->data.nb_subdev);
-       if (err)
-               return err;
-
        platform_set_drvdata(pdev, compo);
 
        return component_add(&pdev->dev, &sti_compositor_ops);
index 019eb44c62cc4c51923dac410f67c158613ff6f4..1a4a73dab11e94f8451ec8f4805894b2d99a6a57 100644 (file)
 #include <linux/clk.h>
 #include <linux/kernel.h>
 
-#include "sti_layer.h"
 #include "sti_mixer.h"
+#include "sti_plane.h"
 
 #define WAIT_NEXT_VSYNC_MS      50 /*ms*/
 
-#define STI_MAX_LAYER 8
 #define STI_MAX_MIXER 2
+#define STI_MAX_VID   1
 
 enum sti_compositor_subdev_type {
        STI_MIXER_MAIN_SUBDEV,
@@ -59,11 +59,9 @@ struct sti_compositor_data {
  * @rst_main: reset control of the main path
  * @rst_aux: reset control of the aux path
  * @mixer: array of mixers
+ * @vid: array of vids
  * @vtg_main: vtg for main data path
  * @vtg_aux: vtg for auxillary data path
- * @layer: array of layers
- * @nb_mixers: number of mixers for this compositor
- * @nb_layers: number of layers (GDP,VID,...) for this compositor
  * @vtg_vblank_nb: callback for VTG VSYNC notification
  */
 struct sti_compositor {
@@ -77,11 +75,9 @@ struct sti_compositor {
        struct reset_control *rst_main;
        struct reset_control *rst_aux;
        struct sti_mixer *mixer[STI_MAX_MIXER];
+       struct sti_vid *vid[STI_MAX_VID];
        struct sti_vtg *vtg_main;
        struct sti_vtg *vtg_aux;
-       struct sti_layer *layer[STI_MAX_LAYER];
-       int nb_mixers;
-       int nb_layers;
        struct notifier_block vtg_vblank_nb;
 };
 
similarity index 56%
rename from drivers/gpu/drm/sti/sti_drm_crtc.c
rename to drivers/gpu/drm/sti/sti_crtc.c
index 6b641c5a2ec7d10609f20a38cbe6bab56c9f4c5e..018ffc970e96e6cd209935c2e6c5f480a4676ebb 100644 (file)
 #include <drm/drm_plane_helper.h>
 
 #include "sti_compositor.h"
-#include "sti_drm_drv.h"
-#include "sti_drm_crtc.h"
+#include "sti_crtc.h"
+#include "sti_drv.h"
+#include "sti_vid.h"
 #include "sti_vtg.h"
 
-static void sti_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
-       DRM_DEBUG_KMS("\n");
-}
-
-static void sti_drm_crtc_prepare(struct drm_crtc *crtc)
+static void sti_crtc_enable(struct drm_crtc *crtc)
 {
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        struct device *dev = mixer->dev;
        struct sti_compositor *compo = dev_get_drvdata(dev);
 
-       mixer->enabled = true;
+       DRM_DEBUG_DRIVER("\n");
+
+       mixer->status = STI_MIXER_READY;
 
        /* Prepare and enable the compo IP clock */
        if (mixer->id == STI_MIXER_MAIN) {
@@ -41,45 +39,28 @@ static void sti_drm_crtc_prepare(struct drm_crtc *crtc)
                        DRM_INFO("Failed to prepare/enable compo_aux clk\n");
        }
 
-       sti_mixer_clear_all_layers(mixer);
+       drm_crtc_vblank_on(crtc);
 }
 
-static void sti_drm_crtc_commit(struct drm_crtc *crtc)
+static void sti_crtc_disabling(struct drm_crtc *crtc)
 {
        struct sti_mixer *mixer = to_sti_mixer(crtc);
-       struct device *dev = mixer->dev;
-       struct sti_compositor *compo = dev_get_drvdata(dev);
-       struct sti_layer *layer;
-
-       if ((!mixer || !compo)) {
-               DRM_ERROR("Can not find mixer or compositor)\n");
-               return;
-       }
 
-       /* get GDP which is reserved to the CRTC FB */
-       layer = to_sti_layer(crtc->primary);
-       if (layer)
-               sti_layer_commit(layer);
-       else
-               DRM_ERROR("Can not find CRTC dedicated plane (GDP0)\n");
-
-       /* Enable layer on mixer */
-       if (sti_mixer_set_layer_status(mixer, layer, true))
-               DRM_ERROR("Can not enable layer at mixer\n");
+       DRM_DEBUG_DRIVER("\n");
 
-       drm_crtc_vblank_on(crtc);
+       mixer->status = STI_MIXER_DISABLING;
 }
 
-static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc,
-                                   const struct drm_display_mode *mode,
-                                   struct drm_display_mode *adjusted_mode)
+static bool sti_crtc_mode_fixup(struct drm_crtc *crtc,
+                               const struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
 {
        /* accept the provided drm_display_mode, do not fix it up */
        return true;
 }
 
 static int
-sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
+sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
 {
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        struct device *dev = mixer->dev;
@@ -122,22 +103,19 @@ sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
 
        res = sti_mixer_active_video_area(mixer, &crtc->mode);
        if (res) {
-               DRM_ERROR("Can not set active video area\n");
+               DRM_ERROR("Can't set active video area\n");
                return -EINVAL;
        }
 
        return res;
 }
 
-static void sti_drm_crtc_disable(struct drm_crtc *crtc)
+static void sti_crtc_disable(struct drm_crtc *crtc)
 {
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        struct device *dev = mixer->dev;
        struct sti_compositor *compo = dev_get_drvdata(dev);
 
-       if (!mixer->enabled)
-               return;
-
        DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
 
        /* Disable Background */
@@ -154,17 +132,18 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
                clk_disable_unprepare(compo->clk_compo_aux);
        }
 
-       mixer->enabled = false;
+       mixer->status = STI_MIXER_DISABLED;
 }
 
 static void
-sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
+sti_crtc_mode_set_nofb(struct drm_crtc *crtc)
 {
-       sti_drm_crtc_prepare(crtc);
-       sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
+       sti_crtc_enable(crtc);
+       sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
 }
 
-static void sti_drm_atomic_begin(struct drm_crtc *crtc)
+static void sti_crtc_atomic_begin(struct drm_crtc *crtc,
+                                 struct drm_crtc_state *old_crtc_state)
 {
        struct sti_mixer *mixer = to_sti_mixer(crtc);
 
@@ -178,46 +157,109 @@ static void sti_drm_atomic_begin(struct drm_crtc *crtc)
        }
 }
 
-static void sti_drm_atomic_flush(struct drm_crtc *crtc)
+static void sti_crtc_atomic_flush(struct drm_crtc *crtc,
+                                 struct drm_crtc_state *old_crtc_state)
 {
+       struct drm_device *drm_dev = crtc->dev;
+       struct sti_mixer *mixer = to_sti_mixer(crtc);
+       struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
+       struct drm_plane *p;
+
+       DRM_DEBUG_DRIVER("\n");
+
+       /* perform plane actions */
+       list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
+               struct sti_plane *plane = to_sti_plane(p);
+
+               switch (plane->status) {
+               case STI_PLANE_UPDATED:
+                       /* update planes tag as updated */
+                       DRM_DEBUG_DRIVER("update plane %s\n",
+                                        sti_plane_to_str(plane));
+
+                       if (sti_mixer_set_plane_depth(mixer, plane)) {
+                               DRM_ERROR("Cannot set plane %s depth\n",
+                                         sti_plane_to_str(plane));
+                               break;
+                       }
+
+                       if (sti_mixer_set_plane_status(mixer, plane, true)) {
+                               DRM_ERROR("Cannot enable plane %s at mixer\n",
+                                         sti_plane_to_str(plane));
+                               break;
+                       }
+
+                       /* if plane is HQVDP_0 then commit the vid[0] */
+                       if (plane->desc == STI_HQVDP_0)
+                               sti_vid_commit(compo->vid[0], p->state);
+
+                       plane->status = STI_PLANE_READY;
+
+                       break;
+               case STI_PLANE_DISABLING:
+                       /* disabling sequence for planes tag as disabling */
+                       DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
+                                        sti_plane_to_str(plane));
+
+                       if (sti_mixer_set_plane_status(mixer, plane, false)) {
+                               DRM_ERROR("Cannot disable plane %s at mixer\n",
+                                         sti_plane_to_str(plane));
+                               continue;
+                       }
+
+                       if (plane->desc == STI_CURSOR)
+                               /* tag plane status for disabled */
+                               plane->status = STI_PLANE_DISABLED;
+                       else
+                               /* tag plane status for flushing */
+                               plane->status = STI_PLANE_FLUSHING;
+
+                       /* if plane is HQVDP_0 then disable the vid[0] */
+                       if (plane->desc == STI_HQVDP_0)
+                               sti_vid_disable(compo->vid[0]);
+
+                       break;
+               default:
+                       /* Other status case are not handled */
+                       break;
+               }
+       }
 }
 
 static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
-       .dpms = sti_drm_crtc_dpms,
-       .prepare = sti_drm_crtc_prepare,
-       .commit = sti_drm_crtc_commit,
-       .mode_fixup = sti_drm_crtc_mode_fixup,
+       .enable = sti_crtc_enable,
+       .disable = sti_crtc_disabling,
+       .mode_fixup = sti_crtc_mode_fixup,
        .mode_set = drm_helper_crtc_mode_set,
-       .mode_set_nofb = sti_drm_crtc_mode_set_nofb,
+       .mode_set_nofb = sti_crtc_mode_set_nofb,
        .mode_set_base = drm_helper_crtc_mode_set_base,
-       .disable = sti_drm_crtc_disable,
-       .atomic_begin = sti_drm_atomic_begin,
-       .atomic_flush = sti_drm_atomic_flush,
+       .atomic_begin = sti_crtc_atomic_begin,
+       .atomic_flush = sti_crtc_atomic_flush,
 };
 
-static void sti_drm_crtc_destroy(struct drm_crtc *crtc)
+static void sti_crtc_destroy(struct drm_crtc *crtc)
 {
        DRM_DEBUG_KMS("\n");
        drm_crtc_cleanup(crtc);
 }
 
-static int sti_drm_crtc_set_property(struct drm_crtc *crtc,
-                                    struct drm_property *property,
-                                    uint64_t val)
+static int sti_crtc_set_property(struct drm_crtc *crtc,
+                                struct drm_property *property,
+                                uint64_t val)
 {
        DRM_DEBUG_KMS("\n");
        return 0;
 }
 
-int sti_drm_crtc_vblank_cb(struct notifier_block *nb,
-                          unsigned long event, void *data)
+int sti_crtc_vblank_cb(struct notifier_block *nb,
+                      unsigned long event, void *data)
 {
        struct drm_device *drm_dev;
        struct sti_compositor *compo =
                container_of(nb, struct sti_compositor, vtg_vblank_nb);
        int *crtc = data;
        unsigned long flags;
-       struct sti_drm_private *priv;
+       struct sti_private *priv;
 
        drm_dev = compo->mixer[*crtc]->drm_crtc.dev;
        priv = drm_dev->dev_private;
@@ -233,21 +275,38 @@ int sti_drm_crtc_vblank_cb(struct notifier_block *nb,
        spin_lock_irqsave(&drm_dev->event_lock, flags);
        if (compo->mixer[*crtc]->pending_event) {
                drm_send_vblank_event(drm_dev, -1,
-                               compo->mixer[*crtc]->pending_event);
+                                     compo->mixer[*crtc]->pending_event);
                drm_vblank_put(drm_dev, *crtc);
                compo->mixer[*crtc]->pending_event = NULL;
        }
        spin_unlock_irqrestore(&drm_dev->event_lock, flags);
 
+       if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) {
+               struct drm_plane *p;
+
+               /* Disable mixer only if all overlay planes (GDP and VDP)
+                * are disabled */
+               list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
+                       struct sti_plane *plane = to_sti_plane(p);
+
+                       if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
+                               if (plane->status != STI_PLANE_DISABLED)
+                                       return 0;
+               }
+               sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc);
+       }
+
        return 0;
 }
 
-int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
+int sti_crtc_enable_vblank(struct drm_device *dev, int crtc)
 {
-       struct sti_drm_private *dev_priv = dev->dev_private;
+       struct sti_private *dev_priv = dev->dev_private;
        struct sti_compositor *compo = dev_priv->compo;
        struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
 
+       DRM_DEBUG_DRIVER("\n");
+
        if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ?
                        compo->vtg_main : compo->vtg_aux,
                        vtg_vblank_nb, crtc)) {
@@ -257,11 +316,11 @@ int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
 
        return 0;
 }
-EXPORT_SYMBOL(sti_drm_crtc_enable_vblank);
+EXPORT_SYMBOL(sti_crtc_enable_vblank);
 
-void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
+void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc)
 {
-       struct sti_drm_private *priv = dev->dev_private;
+       struct sti_private *priv = drm_dev->dev_private;
        struct sti_compositor *compo = priv->compo;
        struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
 
@@ -273,23 +332,23 @@ void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
 
        /* free the resources of the pending requests */
        if (compo->mixer[crtc]->pending_event) {
-               drm_vblank_put(dev, crtc);
+               drm_vblank_put(drm_dev, crtc);
                compo->mixer[crtc]->pending_event = NULL;
        }
 }
-EXPORT_SYMBOL(sti_drm_crtc_disable_vblank);
+EXPORT_SYMBOL(sti_crtc_disable_vblank);
 
 static struct drm_crtc_funcs sti_crtc_funcs = {
        .set_config = drm_atomic_helper_set_config,
        .page_flip = drm_atomic_helper_page_flip,
-       .destroy = sti_drm_crtc_destroy,
-       .set_property = sti_drm_crtc_set_property,
+       .destroy = sti_crtc_destroy,
+       .set_property = sti_crtc_set_property,
        .reset = drm_atomic_helper_crtc_reset,
        .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
        .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 };
 
-bool sti_drm_crtc_is_main(struct drm_crtc *crtc)
+bool sti_crtc_is_main(struct drm_crtc *crtc)
 {
        struct sti_mixer *mixer = to_sti_mixer(crtc);
 
@@ -298,18 +357,18 @@ bool sti_drm_crtc_is_main(struct drm_crtc *crtc)
 
        return false;
 }
-EXPORT_SYMBOL(sti_drm_crtc_is_main);
+EXPORT_SYMBOL(sti_crtc_is_main);
 
-int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
-               struct drm_plane *primary, struct drm_plane *cursor)
+int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
+                 struct drm_plane *primary, struct drm_plane *cursor)
 {
        struct drm_crtc *crtc = &mixer->drm_crtc;
        int res;
 
        res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
-                       &sti_crtc_funcs);
+                                       &sti_crtc_funcs);
        if (res) {
-               DRM_ERROR("Can not initialze CRTC\n");
+               DRM_ERROR("Can't initialze CRTC\n");
                return -EINVAL;
        }
 
diff --git a/drivers/gpu/drm/sti/sti_crtc.h b/drivers/gpu/drm/sti/sti_crtc.h
new file mode 100644 (file)
index 0000000..51963e6
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2014
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _STI_CRTC_H_
+#define _STI_CRTC_H_
+
+#include <drm/drmP.h>
+
+struct sti_mixer;
+
+int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
+                 struct drm_plane *primary, struct drm_plane *cursor);
+int sti_crtc_enable_vblank(struct drm_device *dev, int crtc);
+void sti_crtc_disable_vblank(struct drm_device *dev, int crtc);
+int sti_crtc_vblank_cb(struct notifier_block *nb,
+                      unsigned long event, void *data);
+bool sti_crtc_is_main(struct drm_crtc *drm_crtc);
+
+#endif
index 010eaee60bf7c17c27f5e8e3d14f76771e161ccd..dd10321950518587b9fc06776f2ca2478572bcc3 100644 (file)
@@ -7,8 +7,14 @@
  */
 #include <drm/drmP.h>
 
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include "sti_compositor.h"
 #include "sti_cursor.h"
-#include "sti_layer.h"
+#include "sti_plane.h"
 #include "sti_vtg.h"
 
 /* Registers */
@@ -42,15 +48,19 @@ struct dma_pixmap {
 /**
  * STI Cursor structure
  *
- * @layer:      layer structure
- * @width:      cursor width
- * @height:     cursor height
- * @clut:       color look up table
- * @clut_paddr: color look up table physical address
- * @pixmap:     pixmap dma buffer (clut8-format cursor)
+ * @sti_plane:    sti_plane structure
+ * @dev:          driver device
+ * @regs:         cursor registers
+ * @width:        cursor width
+ * @height:       cursor height
+ * @clut:         color look up table
+ * @clut_paddr:   color look up table physical address
+ * @pixmap:       pixmap dma buffer (clut8-format cursor)
  */
 struct sti_cursor {
-       struct sti_layer layer;
+       struct sti_plane plane;
+       struct device *dev;
+       void __iomem *regs;
        unsigned int width;
        unsigned int height;
        unsigned short *clut;
@@ -62,22 +72,10 @@ static const uint32_t cursor_supported_formats[] = {
        DRM_FORMAT_ARGB8888,
 };
 
-#define to_sti_cursor(x) container_of(x, struct sti_cursor, layer)
-
-static const uint32_t *sti_cursor_get_formats(struct sti_layer *layer)
-{
-       return cursor_supported_formats;
-}
-
-static unsigned int sti_cursor_get_nb_formats(struct sti_layer *layer)
-{
-       return ARRAY_SIZE(cursor_supported_formats);
-}
+#define to_sti_cursor(x) container_of(x, struct sti_cursor, plane)
 
-static void sti_cursor_argb8888_to_clut8(struct sti_layer *layer)
+static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src)
 {
-       struct sti_cursor *cursor = to_sti_cursor(layer);
-       u32 *src = layer->vaddr;
        u8  *dst = cursor->pixmap.base;
        unsigned int i, j;
        u32 a, r, g, b;
@@ -96,127 +94,155 @@ static void sti_cursor_argb8888_to_clut8(struct sti_layer *layer)
        }
 }
 
-static int sti_cursor_prepare_layer(struct sti_layer *layer, bool first_prepare)
+static void sti_cursor_init(struct sti_cursor *cursor)
 {
-       struct sti_cursor *cursor = to_sti_cursor(layer);
-       struct drm_display_mode *mode = layer->mode;
+       unsigned short *base = cursor->clut;
+       unsigned int a, r, g, b;
+
+       /* Assign CLUT values, ARGB444 format */
+       for (a = 0; a < 4; a++)
+               for (r = 0; r < 4; r++)
+                       for (g = 0; g < 4; g++)
+                               for (b = 0; b < 4; b++)
+                                       *base++ = (a * 5) << 12 |
+                                                 (r * 5) << 8 |
+                                                 (g * 5) << 4 |
+                                                 (b * 5);
+}
+
+static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
+                                    struct drm_plane_state *oldstate)
+{
+       struct drm_plane_state *state = drm_plane->state;
+       struct sti_plane *plane = to_sti_plane(drm_plane);
+       struct sti_cursor *cursor = to_sti_cursor(plane);
+       struct drm_crtc *crtc = state->crtc;
+       struct sti_mixer *mixer = to_sti_mixer(crtc);
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_display_mode *mode = &crtc->mode;
+       int dst_x = state->crtc_x;
+       int dst_y = state->crtc_y;
+       int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
+       int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+       /* src_x are in 16.16 format */
+       int src_w = state->src_w >> 16;
+       int src_h = state->src_h >> 16;
+       bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
+       struct drm_gem_cma_object *cma_obj;
        u32 y, x;
        u32 val;
 
-       DRM_DEBUG_DRIVER("\n");
+       DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
+                     crtc->base.id, sti_mixer_to_str(mixer),
+                     drm_plane->base.id, sti_plane_to_str(plane));
+       DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y);
 
-       dev_dbg(layer->dev, "%s %s\n", __func__, sti_layer_to_str(layer));
+       dev_dbg(cursor->dev, "%s %s\n", __func__,
+               sti_plane_to_str(plane));
 
-       if (layer->src_w < STI_CURS_MIN_SIZE ||
-           layer->src_h < STI_CURS_MIN_SIZE ||
-           layer->src_w > STI_CURS_MAX_SIZE ||
-           layer->src_h > STI_CURS_MAX_SIZE) {
+       if (src_w < STI_CURS_MIN_SIZE ||
+           src_h < STI_CURS_MIN_SIZE ||
+           src_w > STI_CURS_MAX_SIZE ||
+           src_h > STI_CURS_MAX_SIZE) {
                DRM_ERROR("Invalid cursor size (%dx%d)\n",
-                               layer->src_w, layer->src_h);
-               return -EINVAL;
+                               src_w, src_h);
+               return;
        }
 
        /* If the cursor size has changed, re-allocated the pixmap */
        if (!cursor->pixmap.base ||
-           (cursor->width != layer->src_w) ||
-           (cursor->height != layer->src_h)) {
-               cursor->width = layer->src_w;
-               cursor->height = layer->src_h;
+           (cursor->width != src_w) ||
+           (cursor->height != src_h)) {
+               cursor->width = src_w;
+               cursor->height = src_h;
 
                if (cursor->pixmap.base)
-                       dma_free_writecombine(layer->dev,
+                       dma_free_writecombine(cursor->dev,
                                              cursor->pixmap.size,
                                              cursor->pixmap.base,
                                              cursor->pixmap.paddr);
 
                cursor->pixmap.size = cursor->width * cursor->height;
 
-               cursor->pixmap.base = dma_alloc_writecombine(layer->dev,
+               cursor->pixmap.base = dma_alloc_writecombine(cursor->dev,
                                                        cursor->pixmap.size,
                                                        &cursor->pixmap.paddr,
                                                        GFP_KERNEL | GFP_DMA);
                if (!cursor->pixmap.base) {
                        DRM_ERROR("Failed to allocate memory for pixmap\n");
-                       return -ENOMEM;
+                       return;
                }
        }
 
+       cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+       if (!cma_obj) {
+               DRM_ERROR("Can't get CMA GEM object for fb\n");
+               return;
+       }
+
        /* Convert ARGB8888 to CLUT8 */
-       sti_cursor_argb8888_to_clut8(layer);
+       sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr);
 
        /* AWS and AWE depend on the mode */
        y = sti_vtg_get_line_number(*mode, 0);
        x = sti_vtg_get_pixel_number(*mode, 0);
        val = y << 16 | x;
-       writel(val, layer->regs + CUR_AWS);
+       writel(val, cursor->regs + CUR_AWS);
        y = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
        x = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
        val = y << 16 | x;
-       writel(val, layer->regs + CUR_AWE);
+       writel(val, cursor->regs + CUR_AWE);
 
        if (first_prepare) {
                /* Set and fetch CLUT */
-               writel(cursor->clut_paddr, layer->regs + CUR_CML);
-               writel(CUR_CTL_CLUT_UPDATE, layer->regs + CUR_CTL);
+               writel(cursor->clut_paddr, cursor->regs + CUR_CML);
+               writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
        }
 
-       return 0;
-}
-
-static int sti_cursor_commit_layer(struct sti_layer *layer)
-{
-       struct sti_cursor *cursor = to_sti_cursor(layer);
-       struct drm_display_mode *mode = layer->mode;
-       u32 ydo, xdo;
-
-       dev_dbg(layer->dev, "%s %s\n", __func__, sti_layer_to_str(layer));
-
        /* Set memory location, size, and position */
-       writel(cursor->pixmap.paddr, layer->regs + CUR_PML);
-       writel(cursor->width, layer->regs + CUR_PMP);
-       writel(cursor->height << 16 | cursor->width, layer->regs + CUR_SIZE);
+       writel(cursor->pixmap.paddr, cursor->regs + CUR_PML);
+       writel(cursor->width, cursor->regs + CUR_PMP);
+       writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE);
 
-       ydo = sti_vtg_get_line_number(*mode, layer->dst_y);
-       xdo = sti_vtg_get_pixel_number(*mode, layer->dst_y);
-       writel((ydo << 16) | xdo, layer->regs + CUR_VPO);
+       y = sti_vtg_get_line_number(*mode, dst_y);
+       x = sti_vtg_get_pixel_number(*mode, dst_y);
+       writel((y << 16) | x, cursor->regs + CUR_VPO);
 
-       return 0;
+       plane->status = STI_PLANE_UPDATED;
 }
 
-static int sti_cursor_disable_layer(struct sti_layer *layer)
+static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
+                                     struct drm_plane_state *oldstate)
 {
-       return 0;
-}
+       struct sti_plane *plane = to_sti_plane(drm_plane);
+       struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
 
-static void sti_cursor_init(struct sti_layer *layer)
-{
-       struct sti_cursor *cursor = to_sti_cursor(layer);
-       unsigned short *base = cursor->clut;
-       unsigned int a, r, g, b;
+       if (!drm_plane->crtc) {
+               DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
+                                drm_plane->base.id);
+               return;
+       }
 
-       /* Assign CLUT values, ARGB444 format */
-       for (a = 0; a < 4; a++)
-               for (r = 0; r < 4; r++)
-                       for (g = 0; g < 4; g++)
-                               for (b = 0; b < 4; b++)
-                                       *base++ = (a * 5) << 12 |
-                                                 (r * 5) << 8 |
-                                                 (g * 5) << 4 |
-                                                 (b * 5);
+       DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
+                        drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
+                        drm_plane->base.id, sti_plane_to_str(plane));
+
+       plane->status = STI_PLANE_DISABLING;
 }
 
-static const struct sti_layer_funcs cursor_ops = {
-       .get_formats = sti_cursor_get_formats,
-       .get_nb_formats = sti_cursor_get_nb_formats,
-       .init = sti_cursor_init,
-       .prepare = sti_cursor_prepare_layer,
-       .commit = sti_cursor_commit_layer,
-       .disable = sti_cursor_disable_layer,
+static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
+       .atomic_update = sti_cursor_atomic_update,
+       .atomic_disable = sti_cursor_atomic_disable,
 };
 
-struct sti_layer *sti_cursor_create(struct device *dev)
+struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
+                                   struct device *dev, int desc,
+                                   void __iomem *baseaddr,
+                                   unsigned int possible_crtcs)
 {
        struct sti_cursor *cursor;
+       size_t size;
+       int res;
 
        cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL);
        if (!cursor) {
@@ -225,18 +251,43 @@ struct sti_layer *sti_cursor_create(struct device *dev)
        }
 
        /* Allocate clut buffer */
-       cursor->clut = dma_alloc_writecombine(dev,
-                       0x100 * sizeof(unsigned short),
-                       &cursor->clut_paddr,
-                       GFP_KERNEL | GFP_DMA);
+       size = 0x100 * sizeof(unsigned short);
+       cursor->clut = dma_alloc_writecombine(dev, size, &cursor->clut_paddr,
+                                             GFP_KERNEL | GFP_DMA);
 
        if (!cursor->clut) {
                DRM_ERROR("Failed to allocate memory for cursor clut\n");
-               devm_kfree(dev, cursor);
-               return NULL;
+               goto err_clut;
+       }
+
+       cursor->dev = dev;
+       cursor->regs = baseaddr;
+       cursor->plane.desc = desc;
+       cursor->plane.status = STI_PLANE_DISABLED;
+
+       sti_cursor_init(cursor);
+
+       res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane,
+                                      possible_crtcs,
+                                      &sti_plane_helpers_funcs,
+                                      cursor_supported_formats,
+                                      ARRAY_SIZE(cursor_supported_formats),
+                                      DRM_PLANE_TYPE_CURSOR);
+       if (res) {
+               DRM_ERROR("Failed to initialize universal plane\n");
+               goto err_plane;
        }
 
-       cursor->layer.ops = &cursor_ops;
+       drm_plane_helper_add(&cursor->plane.drm_plane,
+                            &sti_cursor_helpers_funcs);
+
+       sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);
+
+       return &cursor->plane.drm_plane;
 
-       return (struct sti_layer *)cursor;
+err_plane:
+       dma_free_writecombine(dev, size, cursor->clut, cursor->clut_paddr);
+err_clut:
+       devm_kfree(dev, cursor);
+       return NULL;
 }
index 3c9827404f27900e5239ae4140730da415514315..2ee5c10e8b33c7a125278a2f5247247a3769f112 100644 (file)
@@ -7,6 +7,9 @@
 #ifndef _STI_CURSOR_H_
 #define _STI_CURSOR_H_
 
-struct sti_layer *sti_cursor_create(struct device *dev);
+struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
+                                   struct device *dev, int desc,
+                                   void __iomem *baseaddr,
+                                   unsigned int possible_crtcs);
 
 #endif
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.h b/drivers/gpu/drm/sti/sti_drm_crtc.h
deleted file mode 100644 (file)
index caca8b1..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics SA 2014
- * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
- * License terms:  GNU General Public License (GPL), version 2
- */
-
-#ifndef _STI_DRM_CRTC_H_
-#define _STI_DRM_CRTC_H_
-
-#include <drm/drmP.h>
-
-struct sti_mixer;
-
-int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
-               struct drm_plane *primary, struct drm_plane *cursor);
-int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
-void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
-int sti_drm_crtc_vblank_cb(struct notifier_block *nb,
-               unsigned long event, void *data);
-bool sti_drm_crtc_is_main(struct drm_crtc *drm_crtc);
-
-#endif
diff --git a/drivers/gpu/drm/sti/sti_drm_plane.c b/drivers/gpu/drm/sti/sti_drm_plane.c
deleted file mode 100644 (file)
index 64d4ed4..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics SA 2014
- * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
- *          Fabien Dessenne <fabien.dessenne@st.com>
- *          for STMicroelectronics.
- * License terms:  GNU General Public License (GPL), version 2
- */
-
-#include <drm/drmP.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_plane_helper.h>
-
-#include "sti_compositor.h"
-#include "sti_drm_drv.h"
-#include "sti_drm_plane.h"
-#include "sti_vtg.h"
-
-enum sti_layer_desc sti_layer_default_zorder[] = {
-       STI_GDP_0,
-       STI_VID_0,
-       STI_GDP_1,
-       STI_VID_1,
-       STI_GDP_2,
-       STI_GDP_3,
-};
-
-/* (Background) < GDP0 < VID0 < GDP1 < VID1 < GDP2 < GDP3 < (ForeGround) */
-
-static int
-sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
-                    struct drm_framebuffer *fb, int crtc_x, int crtc_y,
-                    unsigned int crtc_w, unsigned int crtc_h,
-                    uint32_t src_x, uint32_t src_y,
-                    uint32_t src_w, uint32_t src_h)
-{
-       struct sti_layer *layer = to_sti_layer(plane);
-       struct sti_mixer *mixer = to_sti_mixer(crtc);
-       int res;
-
-       DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
-                     crtc->base.id, sti_mixer_to_str(mixer),
-                     plane->base.id, sti_layer_to_str(layer));
-       DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", crtc_w, crtc_h, crtc_x, crtc_y);
-
-       res = sti_mixer_set_layer_depth(mixer, layer);
-       if (res) {
-               DRM_ERROR("Can not set layer depth\n");
-               return res;
-       }
-
-       /* src_x are in 16.16 format. */
-       res = sti_layer_prepare(layer, crtc, fb,
-                       &crtc->mode, mixer->id,
-                       crtc_x, crtc_y, crtc_w, crtc_h,
-                       src_x >> 16, src_y >> 16,
-                       src_w >> 16, src_h >> 16);
-       if (res) {
-               DRM_ERROR("Layer prepare failed\n");
-               return res;
-       }
-
-       res = sti_layer_commit(layer);
-       if (res) {
-               DRM_ERROR("Layer commit failed\n");
-               return res;
-       }
-
-       res = sti_mixer_set_layer_status(mixer, layer, true);
-       if (res) {
-               DRM_ERROR("Can not enable layer at mixer\n");
-               return res;
-       }
-
-       return 0;
-}
-
-static int sti_drm_disable_plane(struct drm_plane *plane)
-{
-       struct sti_layer *layer;
-       struct sti_mixer *mixer;
-       int lay_res, mix_res;
-
-       if (!plane->crtc) {
-               DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", plane->base.id);
-               return 0;
-       }
-       layer = to_sti_layer(plane);
-       mixer = to_sti_mixer(plane->crtc);
-
-       DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
-                       plane->crtc->base.id, sti_mixer_to_str(mixer),
-                       plane->base.id, sti_layer_to_str(layer));
-
-       /* Disable layer at mixer level */
-       mix_res = sti_mixer_set_layer_status(mixer, layer, false);
-       if (mix_res)
-               DRM_ERROR("Can not disable layer at mixer\n");
-
-       /* Wait a while to be sure that a Vsync event is received */
-       msleep(WAIT_NEXT_VSYNC_MS);
-
-       /* Then disable layer itself */
-       lay_res = sti_layer_disable(layer);
-       if (lay_res)
-               DRM_ERROR("Layer disable failed\n");
-
-       if (lay_res || mix_res)
-               return -EINVAL;
-
-       return 0;
-}
-
-static void sti_drm_plane_destroy(struct drm_plane *plane)
-{
-       DRM_DEBUG_DRIVER("\n");
-
-       drm_plane_helper_disable(plane);
-       drm_plane_cleanup(plane);
-}
-
-static int sti_drm_plane_set_property(struct drm_plane *plane,
-                                     struct drm_property *property,
-                                     uint64_t val)
-{
-       struct drm_device *dev = plane->dev;
-       struct sti_drm_private *private = dev->dev_private;
-       struct sti_layer *layer = to_sti_layer(plane);
-
-       DRM_DEBUG_DRIVER("\n");
-
-       if (property == private->plane_zorder_property) {
-               layer->zorder = val;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static struct drm_plane_funcs sti_drm_plane_funcs = {
-       .update_plane = drm_atomic_helper_update_plane,
-       .disable_plane = drm_atomic_helper_disable_plane,
-       .destroy = sti_drm_plane_destroy,
-       .set_property = sti_drm_plane_set_property,
-       .reset = drm_atomic_helper_plane_reset,
-       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
-       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
-};
-
-static int sti_drm_plane_prepare_fb(struct drm_plane *plane,
-                                 struct drm_framebuffer *fb,
-                                 const struct drm_plane_state *new_state)
-{
-       return 0;
-}
-
-static void sti_drm_plane_cleanup_fb(struct drm_plane *plane,
-                                  struct drm_framebuffer *fb,
-                                  const struct drm_plane_state *old_fb)
-{
-}
-
-static int sti_drm_plane_atomic_check(struct drm_plane *plane,
-                                     struct drm_plane_state *state)
-{
-       return 0;
-}
-
-static void sti_drm_plane_atomic_update(struct drm_plane *plane,
-                                       struct drm_plane_state *oldstate)
-{
-       struct drm_plane_state *state = plane->state;
-
-       sti_drm_update_plane(plane, state->crtc, state->fb,
-                           state->crtc_x, state->crtc_y,
-                           state->crtc_w, state->crtc_h,
-                           state->src_x, state->src_y,
-                           state->src_w, state->src_h);
-}
-
-static void sti_drm_plane_atomic_disable(struct drm_plane *plane,
-                                        struct drm_plane_state *oldstate)
-{
-       sti_drm_disable_plane(plane);
-}
-
-static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = {
-       .prepare_fb = sti_drm_plane_prepare_fb,
-       .cleanup_fb = sti_drm_plane_cleanup_fb,
-       .atomic_check = sti_drm_plane_atomic_check,
-       .atomic_update = sti_drm_plane_atomic_update,
-       .atomic_disable = sti_drm_plane_atomic_disable,
-};
-
-static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane,
-                                                uint64_t default_val)
-{
-       struct drm_device *dev = plane->dev;
-       struct sti_drm_private *private = dev->dev_private;
-       struct drm_property *prop;
-       struct sti_layer *layer = to_sti_layer(plane);
-
-       prop = private->plane_zorder_property;
-       if (!prop) {
-               prop = drm_property_create_range(dev, 0, "zpos", 0,
-                                                GAM_MIXER_NB_DEPTH_LEVEL - 1);
-               if (!prop)
-                       return;
-
-               private->plane_zorder_property = prop;
-       }
-
-       drm_object_attach_property(&plane->base, prop, default_val);
-       layer->zorder = default_val;
-}
-
-struct drm_plane *sti_drm_plane_init(struct drm_device *dev,
-                                    struct sti_layer *layer,
-                                    unsigned int possible_crtcs,
-                                    enum drm_plane_type type)
-{
-       int err, i;
-       uint64_t default_zorder = 0;
-
-       err = drm_universal_plane_init(dev, &layer->plane, possible_crtcs,
-                            &sti_drm_plane_funcs,
-                            sti_layer_get_formats(layer),
-                            sti_layer_get_nb_formats(layer), type);
-       if (err) {
-               DRM_ERROR("Failed to initialize plane\n");
-               return NULL;
-       }
-
-       drm_plane_helper_add(&layer->plane, &sti_drm_plane_helpers_funcs);
-
-       for (i = 0; i < ARRAY_SIZE(sti_layer_default_zorder); i++)
-               if (sti_layer_default_zorder[i] == layer->desc)
-                       break;
-
-       default_zorder = i + 1;
-
-       if (type == DRM_PLANE_TYPE_OVERLAY)
-               sti_drm_plane_attach_zorder_property(&layer->plane,
-                               default_zorder);
-
-       DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%llu\n",
-                        layer->plane.base.id,
-                        sti_layer_to_str(layer), default_zorder);
-
-       return &layer->plane;
-}
-EXPORT_SYMBOL(sti_drm_plane_init);
diff --git a/drivers/gpu/drm/sti/sti_drm_plane.h b/drivers/gpu/drm/sti/sti_drm_plane.h
deleted file mode 100644 (file)
index 4f19183..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics SA 2014
- * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
- * License terms:  GNU General Public License (GPL), version 2
- */
-
-#ifndef _STI_DRM_PLANE_H_
-#define _STI_DRM_PLANE_H_
-
-#include <drm/drmP.h>
-
-struct sti_layer;
-
-struct drm_plane *sti_drm_plane_init(struct drm_device *dev,
-               struct sti_layer *layer,
-               unsigned int possible_crtcs,
-               enum drm_plane_type type);
-#endif
similarity index 61%
rename from drivers/gpu/drm/sti/sti_drm_drv.c
rename to drivers/gpu/drm/sti/sti_drv.c
index 59d558b400b33f390cdd6db00014ab29c94b84d4..6f4af6a8ba1bf7883b8c04db0c863018f092f275 100644 (file)
@@ -18,8 +18,8 @@
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
-#include "sti_drm_drv.h"
-#include "sti_drm_crtc.h"
+#include "sti_crtc.h"
+#include "sti_drv.h"
 
 #define DRIVER_NAME    "sti"
 #define DRIVER_DESC    "STMicroelectronics SoC DRM"
 #define STI_MAX_FB_HEIGHT      4096
 #define STI_MAX_FB_WIDTH       4096
 
-static void sti_drm_atomic_schedule(struct sti_drm_private *private,
-                                 struct drm_atomic_state *state)
+static void sti_atomic_schedule(struct sti_private *private,
+                               struct drm_atomic_state *state)
 {
        private->commit.state = state;
        schedule_work(&private->commit.work);
 }
 
-static void sti_drm_atomic_complete(struct sti_drm_private *private,
-                                 struct drm_atomic_state *state)
+static void sti_atomic_complete(struct sti_private *private,
+                               struct drm_atomic_state *state)
 {
        struct drm_device *drm = private->drm_dev;
 
@@ -68,18 +68,18 @@ static void sti_drm_atomic_complete(struct sti_drm_private *private,
        drm_atomic_state_free(state);
 }
 
-static void sti_drm_atomic_work(struct work_struct *work)
+static void sti_atomic_work(struct work_struct *work)
 {
-       struct sti_drm_private *private = container_of(work,
-                       struct sti_drm_private, commit.work);
+       struct sti_private *private = container_of(work,
+                       struct sti_private, commit.work);
 
-       sti_drm_atomic_complete(private, private->commit.state);
+       sti_atomic_complete(private, private->commit.state);
 }
 
-static int sti_drm_atomic_commit(struct drm_device *drm,
-                              struct drm_atomic_state *state, bool async)
+static int sti_atomic_commit(struct drm_device *drm,
+                            struct drm_atomic_state *state, bool async)
 {
-       struct sti_drm_private *private = drm->dev_private;
+       struct sti_private *private = drm->dev_private;
        int err;
 
        err = drm_atomic_helper_prepare_planes(drm, state);
@@ -99,21 +99,21 @@ static int sti_drm_atomic_commit(struct drm_device *drm,
        drm_atomic_helper_swap_state(drm, state);
 
        if (async)
-               sti_drm_atomic_schedule(private, state);
+               sti_atomic_schedule(private, state);
        else
-               sti_drm_atomic_complete(private, state);
+               sti_atomic_complete(private, state);
 
        mutex_unlock(&private->commit.lock);
        return 0;
 }
 
-static struct drm_mode_config_funcs sti_drm_mode_config_funcs = {
+static struct drm_mode_config_funcs sti_mode_config_funcs = {
        .fb_create = drm_fb_cma_create,
        .atomic_check = drm_atomic_helper_check,
-       .atomic_commit = sti_drm_atomic_commit,
+       .atomic_commit = sti_atomic_commit,
 };
 
-static void sti_drm_mode_config_init(struct drm_device *dev)
+static void sti_mode_config_init(struct drm_device *dev)
 {
        dev->mode_config.min_width = 0;
        dev->mode_config.min_height = 0;
@@ -126,15 +126,15 @@ static void sti_drm_mode_config_init(struct drm_device *dev)
        dev->mode_config.max_width = STI_MAX_FB_HEIGHT;
        dev->mode_config.max_height = STI_MAX_FB_WIDTH;
 
-       dev->mode_config.funcs = &sti_drm_mode_config_funcs;
+       dev->mode_config.funcs = &sti_mode_config_funcs;
 }
 
-static int sti_drm_load(struct drm_device *dev, unsigned long flags)
+static int sti_load(struct drm_device *dev, unsigned long flags)
 {
-       struct sti_drm_private *private;
+       struct sti_private *private;
        int ret;
 
-       private = kzalloc(sizeof(struct sti_drm_private), GFP_KERNEL);
+       private = kzalloc(sizeof(*private), GFP_KERNEL);
        if (!private) {
                DRM_ERROR("Failed to allocate private\n");
                return -ENOMEM;
@@ -143,12 +143,12 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags)
        private->drm_dev = dev;
 
        mutex_init(&private->commit.lock);
-       INIT_WORK(&private->commit.work, sti_drm_atomic_work);
+       INIT_WORK(&private->commit.work, sti_atomic_work);
 
        drm_mode_config_init(dev);
        drm_kms_helper_poll_init(dev);
 
-       sti_drm_mode_config_init(dev);
+       sti_mode_config_init(dev);
 
        ret = component_bind_all(dev->dev, dev);
        if (ret) {
@@ -162,13 +162,13 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags)
 
 #ifdef CONFIG_DRM_STI_FBDEV
        drm_fbdev_cma_init(dev, 32,
-                  dev->mode_config.num_crtc,
-                  dev->mode_config.num_connector);
+                          dev->mode_config.num_crtc,
+                          dev->mode_config.num_connector);
 #endif
        return 0;
 }
 
-static const struct file_operations sti_drm_driver_fops = {
+static const struct file_operations sti_driver_fops = {
        .owner = THIS_MODULE,
        .open = drm_open,
        .mmap = drm_gem_cma_mmap,
@@ -181,33 +181,33 @@ static const struct file_operations sti_drm_driver_fops = {
        .release = drm_release,
 };
 
-static struct dma_buf *sti_drm_gem_prime_export(struct drm_device *dev,
-                                               struct drm_gem_object *obj,
-                                               int flags)
+static struct dma_buf *sti_gem_prime_export(struct drm_device *dev,
+                                           struct drm_gem_object *obj,
+                                           int flags)
 {
        /* we want to be able to write in mmapped buffer */
        flags |= O_RDWR;
        return drm_gem_prime_export(dev, obj, flags);
 }
 
-static struct drm_driver sti_drm_driver = {
+static struct drm_driver sti_driver = {
        .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET |
            DRIVER_GEM | DRIVER_PRIME,
-       .load = sti_drm_load,
+       .load = sti_load,
        .gem_free_object = drm_gem_cma_free_object,
        .gem_vm_ops = &drm_gem_cma_vm_ops,
        .dumb_create = drm_gem_cma_dumb_create,
        .dumb_map_offset = drm_gem_cma_dumb_map_offset,
        .dumb_destroy = drm_gem_dumb_destroy,
-       .fops = &sti_drm_driver_fops,
+       .fops = &sti_driver_fops,
 
        .get_vblank_counter = drm_vblank_count,
-       .enable_vblank = sti_drm_crtc_enable_vblank,
-       .disable_vblank = sti_drm_crtc_disable_vblank,
+       .enable_vblank = sti_crtc_enable_vblank,
+       .disable_vblank = sti_crtc_disable_vblank,
 
        .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
-       .gem_prime_export = sti_drm_gem_prime_export,
+       .gem_prime_export = sti_gem_prime_export,
        .gem_prime_import = drm_gem_prime_import,
        .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
        .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
@@ -227,30 +227,32 @@ static int compare_of(struct device *dev, void *data)
        return dev->of_node == data;
 }
 
-static int sti_drm_bind(struct device *dev)
+static int sti_bind(struct device *dev)
 {
-       return drm_platform_init(&sti_drm_driver, to_platform_device(dev));
+       return drm_platform_init(&sti_driver, to_platform_device(dev));
 }
 
-static void sti_drm_unbind(struct device *dev)
+static void sti_unbind(struct device *dev)
 {
        drm_put_dev(dev_get_drvdata(dev));
 }
 
-static const struct component_master_ops sti_drm_ops = {
-       .bind = sti_drm_bind,
-       .unbind = sti_drm_unbind,
+static const struct component_master_ops sti_ops = {
+       .bind = sti_bind,
+       .unbind = sti_unbind,
 };
 
-static int sti_drm_master_probe(struct platform_device *pdev)
+static int sti_platform_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *node = dev->parent->of_node;
+       struct device_node *node = dev->of_node;
        struct device_node *child_np;
        struct component_match *match = NULL;
 
        dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
 
+       of_platform_populate(node, NULL, NULL, dev);
+
        child_np = of_get_next_available_child(node, NULL);
 
        while (child_np) {
@@ -259,68 +261,33 @@ static int sti_drm_master_probe(struct platform_device *pdev)
                child_np = of_get_next_available_child(node, child_np);
        }
 
-       return component_master_add_with_match(dev, &sti_drm_ops, match);
-}
-
-static int sti_drm_master_remove(struct platform_device *pdev)
-{
-       component_master_del(&pdev->dev, &sti_drm_ops);
-       return 0;
+       return component_master_add_with_match(dev, &sti_ops, match);
 }
 
-static struct platform_driver sti_drm_master_driver = {
-       .probe = sti_drm_master_probe,
-       .remove = sti_drm_master_remove,
-       .driver = {
-               .name = DRIVER_NAME "__master",
-       },
-};
-
-static int sti_drm_platform_probe(struct platform_device *pdev)
+static int sti_platform_remove(struct platform_device *pdev)
 {
-       struct device *dev = &pdev->dev;
-       struct device_node *node = dev->of_node;
-       struct platform_device *master;
-
-       of_platform_populate(node, NULL, NULL, dev);
-
-       platform_driver_register(&sti_drm_master_driver);
-       master = platform_device_register_resndata(dev,
-                       DRIVER_NAME "__master", -1,
-                       NULL, 0, NULL, 0);
-       if (IS_ERR(master))
-               return PTR_ERR(master);
-
-       platform_set_drvdata(pdev, master);
-       return 0;
-}
-
-static int sti_drm_platform_remove(struct platform_device *pdev)
-{
-       struct platform_device *master = platform_get_drvdata(pdev);
-
+       component_master_del(&pdev->dev, &sti_ops);
        of_platform_depopulate(&pdev->dev);
-       platform_device_unregister(master);
-       platform_driver_unregister(&sti_drm_master_driver);
+
        return 0;
 }
 
-static const struct of_device_id sti_drm_dt_ids[] = {
+static const struct of_device_id sti_dt_ids[] = {
        { .compatible = "st,sti-display-subsystem", },
        { /* end node */ },
 };
-MODULE_DEVICE_TABLE(of, sti_drm_dt_ids);
+MODULE_DEVICE_TABLE(of, sti_dt_ids);
 
-static struct platform_driver sti_drm_platform_driver = {
-       .probe = sti_drm_platform_probe,
-       .remove = sti_drm_platform_remove,
+static struct platform_driver sti_platform_driver = {
+       .probe = sti_platform_probe,
+       .remove = sti_platform_remove,
        .driver = {
                .name = DRIVER_NAME,
-               .of_match_table = sti_drm_dt_ids,
+               .of_match_table = sti_dt_ids,
        },
 };
 
-module_platform_driver(sti_drm_platform_driver);
+module_platform_driver(sti_platform_driver);
 
 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
similarity index 90%
rename from drivers/gpu/drm/sti/sti_drm_drv.h
rename to drivers/gpu/drm/sti/sti_drv.h
index c413aa3ff4021449791f3ce73668d8beabdb94c9..9372f69e1859ff96986b0cea5c795f3d3325c047 100644 (file)
@@ -4,8 +4,8 @@
  * License terms:  GNU General Public License (GPL), version 2
  */
 
-#ifndef _STI_DRM_DRV_H_
-#define _STI_DRM_DRV_H_
+#ifndef _STI_DRV_H_
+#define _STI_DRV_H_
 
 #include <drm/drmP.h>
 
@@ -20,7 +20,7 @@ struct sti_tvout;
  * @plane_zorder_property: z-order property for CRTC planes
  * @drm_dev:               drm device
  */
-struct sti_drm_private {
+struct sti_private {
        struct sti_compositor *compo;
        struct drm_property *plane_zorder_property;
        struct drm_device *drm_dev;
index 087906fd884685a4f22454974ebfd966a05a2f1f..9365670427ad26ef7224b085557c678769c63c6c 100644 (file)
@@ -9,9 +9,12 @@
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
 #include "sti_compositor.h"
 #include "sti_gdp.h"
-#include "sti_layer.h"
+#include "sti_plane.h"
 #include "sti_vtg.h"
 
 #define ALPHASWITCH     BIT(6)
@@ -26,7 +29,7 @@
 #define GDP_XBGR8888    (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH)
 #define GDP_ARGB8565    0x04
 #define GDP_ARGB8888    0x05
-#define GDP_ABGR8888   (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
+#define GDP_ABGR8888    (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
 #define GDP_ARGB1555    0x06
 #define GDP_ARGB4444    0x07
 #define GDP_CLUT8       0x0B
@@ -53,8 +56,8 @@
 #define GAM_GDP_PPT_IGNORE      (BIT(1) | BIT(0))
 #define GAM_GDP_SIZE_MAX        0x7FF
 
-#define GDP_NODE_NB_BANK       2
-#define GDP_NODE_PER_FIELD     2
+#define GDP_NODE_NB_BANK        2
+#define GDP_NODE_PER_FIELD      2
 
 struct sti_gdp_node {
        u32 gam_gdp_ctl;
@@ -85,16 +88,20 @@ struct sti_gdp_node_list {
 /**
  * STI GDP structure
  *
- * @layer:             layer structure
+ * @sti_plane:          sti_plane structure
+ * @dev:                driver device
+ * @regs:               gdp registers
  * @clk_pix:            pixel clock for the current gdp
  * @clk_main_parent:    gdp parent clock if main path used
  * @clk_aux_parent:     gdp parent clock if aux path used
  * @vtg_field_nb:       callback for VTG FIELD (top or bottom) notification
  * @is_curr_top:        true if the current node processed is the top field
- * @node_list:         array of node list
+ * @node_list:          array of node list
  */
 struct sti_gdp {
-       struct sti_layer layer;
+       struct sti_plane plane;
+       struct device *dev;
+       void __iomem *regs;
        struct clk *clk_pix;
        struct clk *clk_main_parent;
        struct clk *clk_aux_parent;
@@ -103,7 +110,7 @@ struct sti_gdp {
        struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK];
 };
 
-#define to_sti_gdp(x) container_of(x, struct sti_gdp, layer)
+#define to_sti_gdp(x) container_of(x, struct sti_gdp, plane)
 
 static const uint32_t gdp_supported_formats[] = {
        DRM_FORMAT_XRGB8888,
@@ -120,16 +127,6 @@ static const uint32_t gdp_supported_formats[] = {
        DRM_FORMAT_C8,
 };
 
-static const uint32_t *sti_gdp_get_formats(struct sti_layer *layer)
-{
-       return gdp_supported_formats;
-}
-
-static unsigned int sti_gdp_get_nb_formats(struct sti_layer *layer)
-{
-       return ARRAY_SIZE(gdp_supported_formats);
-}
-
 static int sti_gdp_fourcc2format(int fourcc)
 {
        switch (fourcc) {
@@ -175,20 +172,19 @@ static int sti_gdp_get_alpharange(int format)
 
 /**
  * sti_gdp_get_free_nodes
- * @layer: gdp layer
+ * @gdp: gdp pointer
  *
  * Look for a GDP node list that is not currently read by the HW.
  *
  * RETURNS:
  * Pointer to the free GDP node list
  */
-static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_layer *layer)
+static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_gdp *gdp)
 {
        int hw_nvn;
-       struct sti_gdp *gdp = to_sti_gdp(layer);
        unsigned int i;
 
-       hw_nvn = readl(layer->regs + GAM_GDP_NVN_OFFSET);
+       hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET);
        if (!hw_nvn)
                goto end;
 
@@ -199,7 +195,7 @@ static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_layer *layer)
 
        /* in hazardious cases restart with the first node */
        DRM_ERROR("inconsistent NVN for %s: 0x%08X\n",
-                       sti_layer_to_str(layer), hw_nvn);
+                       sti_plane_to_str(&gdp->plane), hw_nvn);
 
 end:
        return &gdp->node_list[0];
@@ -207,7 +203,7 @@ end:
 
 /**
  * sti_gdp_get_current_nodes
- * @layer: GDP layer
+ * @gdp: gdp pointer
  *
  * Look for GDP nodes that are currently read by the HW.
  *
@@ -215,13 +211,12 @@ end:
  * Pointer to the current GDP node list
  */
 static
-struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_layer *layer)
+struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_gdp *gdp)
 {
        int hw_nvn;
-       struct sti_gdp *gdp = to_sti_gdp(layer);
        unsigned int i;
 
-       hw_nvn = readl(layer->regs + GAM_GDP_NVN_OFFSET);
+       hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET);
        if (!hw_nvn)
                goto end;
 
@@ -232,205 +227,25 @@ struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_layer *layer)
 
 end:
        DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n",
-                               hw_nvn, sti_layer_to_str(layer));
+                               hw_nvn, sti_plane_to_str(&gdp->plane));
 
        return NULL;
 }
 
 /**
- * sti_gdp_prepare_layer
- * @lay: gdp layer
- * @first_prepare: true if it is the first time this function is called
- *
- * Update the free GDP node list according to the layer properties.
- *
- * RETURNS:
- * 0 on success.
- */
-static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare)
-{
-       struct sti_gdp_node_list *list;
-       struct sti_gdp_node *top_field, *btm_field;
-       struct drm_display_mode *mode = layer->mode;
-       struct device *dev = layer->dev;
-       struct sti_gdp *gdp = to_sti_gdp(layer);
-       struct sti_compositor *compo = dev_get_drvdata(dev);
-       int format;
-       unsigned int depth, bpp;
-       int rate = mode->clock * 1000;
-       int res;
-       u32 ydo, xdo, yds, xds;
-
-       list = sti_gdp_get_free_nodes(layer);
-       top_field = list->top_field;
-       btm_field = list->btm_field;
-
-       dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__,
-                       sti_layer_to_str(layer), top_field, btm_field);
-
-       /* Build the top field from layer params */
-       top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
-       top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
-       format = sti_gdp_fourcc2format(layer->format);
-       if (format == -1) {
-               DRM_ERROR("Format not supported by GDP %.4s\n",
-                         (char *)&layer->format);
-               return 1;
-       }
-       top_field->gam_gdp_ctl |= format;
-       top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
-       top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
-
-       /* pixel memory location */
-       drm_fb_get_bpp_depth(layer->format, &depth, &bpp);
-       top_field->gam_gdp_pml = (u32) layer->paddr + layer->offsets[0];
-       top_field->gam_gdp_pml += layer->src_x * (bpp >> 3);
-       top_field->gam_gdp_pml += layer->src_y * layer->pitches[0];
-
-       /* input parameters */
-       top_field->gam_gdp_pmp = layer->pitches[0];
-       top_field->gam_gdp_size =
-           clamp_val(layer->src_h, 0, GAM_GDP_SIZE_MAX) << 16 |
-           clamp_val(layer->src_w, 0, GAM_GDP_SIZE_MAX);
-
-       /* output parameters */
-       ydo = sti_vtg_get_line_number(*mode, layer->dst_y);
-       yds = sti_vtg_get_line_number(*mode, layer->dst_y + layer->dst_h - 1);
-       xdo = sti_vtg_get_pixel_number(*mode, layer->dst_x);
-       xds = sti_vtg_get_pixel_number(*mode, layer->dst_x + layer->dst_w - 1);
-       top_field->gam_gdp_vpo = (ydo << 16) | xdo;
-       top_field->gam_gdp_vps = (yds << 16) | xds;
-
-       /* Same content and chained together */
-       memcpy(btm_field, top_field, sizeof(*btm_field));
-       top_field->gam_gdp_nvn = list->btm_field_paddr;
-       btm_field->gam_gdp_nvn = list->top_field_paddr;
-
-       /* Interlaced mode */
-       if (layer->mode->flags & DRM_MODE_FLAG_INTERLACE)
-               btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
-                   layer->pitches[0];
-
-       if (first_prepare) {
-               /* Register gdp callback */
-               if (sti_vtg_register_client(layer->mixer_id == STI_MIXER_MAIN ?
-                               compo->vtg_main : compo->vtg_aux,
-                               &gdp->vtg_field_nb, layer->mixer_id)) {
-                       DRM_ERROR("Cannot register VTG notifier\n");
-                       return 1;
-               }
-
-               /* Set and enable gdp clock */
-               if (gdp->clk_pix) {
-                       struct clk *clkp;
-                       /* According to the mixer used, the gdp pixel clock
-                        * should have a different parent clock. */
-                       if (layer->mixer_id == STI_MIXER_MAIN)
-                               clkp = gdp->clk_main_parent;
-                       else
-                               clkp = gdp->clk_aux_parent;
-
-                       if (clkp)
-                               clk_set_parent(gdp->clk_pix, clkp);
-
-                       res = clk_set_rate(gdp->clk_pix, rate);
-                       if (res < 0) {
-                               DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
-                                               rate);
-                               return 1;
-                       }
-
-                       if (clk_prepare_enable(gdp->clk_pix)) {
-                               DRM_ERROR("Failed to prepare/enable gdp\n");
-                               return 1;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/**
- * sti_gdp_commit_layer
- * @lay: gdp layer
- *
- * Update the NVN field of the 'right' field of the current GDP node (being
- * used by the HW) with the address of the updated ('free') top field GDP node.
- * - In interlaced mode the 'right' field is the bottom field as we update
- *   frames starting from their top field
- * - In progressive mode, we update both bottom and top fields which are
- *   equal nodes.
- * At the next VSYNC, the updated node list will be used by the HW.
- *
- * RETURNS:
- * 0 on success.
- */
-static int sti_gdp_commit_layer(struct sti_layer *layer)
-{
-       struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(layer);
-       struct sti_gdp_node *updated_top_node = updated_list->top_field;
-       struct sti_gdp_node *updated_btm_node = updated_list->btm_field;
-       struct sti_gdp *gdp = to_sti_gdp(layer);
-       u32 dma_updated_top = updated_list->top_field_paddr;
-       u32 dma_updated_btm = updated_list->btm_field_paddr;
-       struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(layer);
-
-       dev_dbg(layer->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__,
-                       sti_layer_to_str(layer),
-                       updated_top_node, updated_btm_node);
-       dev_dbg(layer->dev, "Current NVN:0x%X\n",
-               readl(layer->regs + GAM_GDP_NVN_OFFSET));
-       dev_dbg(layer->dev, "Posted buff: %lx current buff: %x\n",
-               (unsigned long)layer->paddr,
-               readl(layer->regs + GAM_GDP_PML_OFFSET));
-
-       if (curr_list == NULL) {
-               /* First update or invalid node should directly write in the
-                * hw register */
-               DRM_DEBUG_DRIVER("%s first update (or invalid node)",
-                               sti_layer_to_str(layer));
-
-               writel(gdp->is_curr_top == true ?
-                               dma_updated_btm : dma_updated_top,
-                               layer->regs + GAM_GDP_NVN_OFFSET);
-               return 0;
-       }
-
-       if (layer->mode->flags & DRM_MODE_FLAG_INTERLACE) {
-               if (gdp->is_curr_top == true) {
-                       /* Do not update in the middle of the frame, but
-                        * postpone the update after the bottom field has
-                        * been displayed */
-                       curr_list->btm_field->gam_gdp_nvn = dma_updated_top;
-               } else {
-                       /* Direct update to avoid one frame delay */
-                       writel(dma_updated_top,
-                               layer->regs + GAM_GDP_NVN_OFFSET);
-               }
-       } else {
-               /* Direct update for progressive to avoid one frame delay */
-               writel(dma_updated_top, layer->regs + GAM_GDP_NVN_OFFSET);
-       }
-
-       return 0;
-}
-
-/**
- * sti_gdp_disable_layer
- * @lay: gdp layer
+ * sti_gdp_disable
+ * @gdp: gdp pointer
  *
  * Disable a GDP.
- *
- * RETURNS:
- * 0 on success.
  */
-static int sti_gdp_disable_layer(struct sti_layer *layer)
+static void sti_gdp_disable(struct sti_gdp *gdp)
 {
+       struct drm_plane *drm_plane = &gdp->plane.drm_plane;
+       struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
+       struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
        unsigned int i;
-       struct sti_gdp *gdp = to_sti_gdp(layer);
-       struct sti_compositor *compo = dev_get_drvdata(layer->dev);
 
-       DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer));
+       DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&gdp->plane));
 
        /* Set the nodes as 'to be ignored on mixer' */
        for (i = 0; i < GDP_NODE_NB_BANK; i++) {
@@ -438,14 +253,14 @@ static int sti_gdp_disable_layer(struct sti_layer *layer)
                gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE;
        }
 
-       if (sti_vtg_unregister_client(layer->mixer_id == STI_MIXER_MAIN ?
+       if (sti_vtg_unregister_client(mixer->id == STI_MIXER_MAIN ?
                        compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb))
                DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
 
        if (gdp->clk_pix)
                clk_disable_unprepare(gdp->clk_pix);
 
-       return 0;
+       gdp->plane.status = STI_PLANE_DISABLED;
 }
 
 /**
@@ -464,6 +279,14 @@ int sti_gdp_field_cb(struct notifier_block *nb,
 {
        struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb);
 
+       if (gdp->plane.status == STI_PLANE_FLUSHING) {
+               /* disable need to be synchronize on vsync event */
+               DRM_DEBUG_DRIVER("Vsync event received => disable %s\n",
+                                sti_plane_to_str(&gdp->plane));
+
+               sti_gdp_disable(gdp);
+       }
+
        switch (event) {
        case VTG_TOP_FIELD_EVENT:
                gdp->is_curr_top = true;
@@ -479,10 +302,9 @@ int sti_gdp_field_cb(struct notifier_block *nb,
        return 0;
 }
 
-static void sti_gdp_init(struct sti_layer *layer)
+static void sti_gdp_init(struct sti_gdp *gdp)
 {
-       struct sti_gdp *gdp = to_sti_gdp(layer);
-       struct device_node *np = layer->dev->of_node;
+       struct device_node *np = gdp->dev->of_node;
        dma_addr_t dma_addr;
        void *base;
        unsigned int i, size;
@@ -490,8 +312,8 @@ static void sti_gdp_init(struct sti_layer *layer)
        /* Allocate all the nodes within a single memory page */
        size = sizeof(struct sti_gdp_node) *
            GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK;
-       base = dma_alloc_writecombine(layer->dev,
-                       size, &dma_addr, GFP_KERNEL | GFP_DMA);
+       base = dma_alloc_writecombine(gdp->dev,
+                                     size, &dma_addr, GFP_KERNEL | GFP_DMA);
 
        if (!base) {
                DRM_ERROR("Failed to allocate memory for GDP node\n");
@@ -526,7 +348,7 @@ static void sti_gdp_init(struct sti_layer *layer)
                /* GDP of STiH407 chip have its own pixel clock */
                char *clk_name;
 
-               switch (layer->desc) {
+               switch (gdp->plane.desc) {
                case STI_GDP_0:
                        clk_name = "pix_gdp1";
                        break;
@@ -544,32 +366,249 @@ static void sti_gdp_init(struct sti_layer *layer)
                        return;
                }
 
-               gdp->clk_pix = devm_clk_get(layer->dev, clk_name);
+               gdp->clk_pix = devm_clk_get(gdp->dev, clk_name);
                if (IS_ERR(gdp->clk_pix))
                        DRM_ERROR("Cannot get %s clock\n", clk_name);
 
-               gdp->clk_main_parent = devm_clk_get(layer->dev, "main_parent");
+               gdp->clk_main_parent = devm_clk_get(gdp->dev, "main_parent");
                if (IS_ERR(gdp->clk_main_parent))
                        DRM_ERROR("Cannot get main_parent clock\n");
 
-               gdp->clk_aux_parent = devm_clk_get(layer->dev, "aux_parent");
+               gdp->clk_aux_parent = devm_clk_get(gdp->dev, "aux_parent");
                if (IS_ERR(gdp->clk_aux_parent))
                        DRM_ERROR("Cannot get aux_parent clock\n");
        }
 }
 
-static const struct sti_layer_funcs gdp_ops = {
-       .get_formats = sti_gdp_get_formats,
-       .get_nb_formats = sti_gdp_get_nb_formats,
-       .init = sti_gdp_init,
-       .prepare = sti_gdp_prepare_layer,
-       .commit = sti_gdp_commit_layer,
-       .disable = sti_gdp_disable_layer,
+static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
+                                 struct drm_plane_state *oldstate)
+{
+       struct drm_plane_state *state = drm_plane->state;
+       struct sti_plane *plane = to_sti_plane(drm_plane);
+       struct sti_gdp *gdp = to_sti_gdp(plane);
+       struct drm_crtc *crtc = state->crtc;
+       struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
+       struct drm_framebuffer *fb =  state->fb;
+       bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
+       struct sti_mixer *mixer;
+       struct drm_display_mode *mode;
+       int dst_x, dst_y, dst_w, dst_h;
+       int src_x, src_y, src_w, src_h;
+       struct drm_gem_cma_object *cma_obj;
+       struct sti_gdp_node_list *list;
+       struct sti_gdp_node_list *curr_list;
+       struct sti_gdp_node *top_field, *btm_field;
+       u32 dma_updated_top;
+       u32 dma_updated_btm;
+       int format;
+       unsigned int depth, bpp;
+       u32 ydo, xdo, yds, xds;
+       int res;
+
+       /* Manage the case where crtc is null (disabled) */
+       if (!crtc)
+               return;
+
+       mixer = to_sti_mixer(crtc);
+       mode = &crtc->mode;
+       dst_x = state->crtc_x;
+       dst_y = state->crtc_y;
+       dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
+       dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+       /* src_x are in 16.16 format */
+       src_x = state->src_x >> 16;
+       src_y = state->src_y >> 16;
+       src_w = state->src_w >> 16;
+       src_h = state->src_h >> 16;
+
+       DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
+                     crtc->base.id, sti_mixer_to_str(mixer),
+                     drm_plane->base.id, sti_plane_to_str(plane));
+       DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
+                     sti_plane_to_str(plane),
+                     dst_w, dst_h, dst_x, dst_y,
+                     src_w, src_h, src_x, src_y);
+
+       list = sti_gdp_get_free_nodes(gdp);
+       top_field = list->top_field;
+       btm_field = list->btm_field;
+
+       dev_dbg(gdp->dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__,
+               sti_plane_to_str(plane), top_field, btm_field);
+
+       /* build the top field */
+       top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
+       top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
+       format = sti_gdp_fourcc2format(fb->pixel_format);
+       if (format == -1) {
+               DRM_ERROR("Format not supported by GDP %.4s\n",
+                         (char *)&fb->pixel_format);
+               return;
+       }
+       top_field->gam_gdp_ctl |= format;
+       top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
+       top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
+
+       cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+       if (!cma_obj) {
+               DRM_ERROR("Can't get CMA GEM object for fb\n");
+               return;
+       }
+
+       DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
+                        (char *)&fb->pixel_format,
+                        (unsigned long)cma_obj->paddr);
+
+       /* pixel memory location */
+       drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
+       top_field->gam_gdp_pml = (u32)cma_obj->paddr + fb->offsets[0];
+       top_field->gam_gdp_pml += src_x * (bpp >> 3);
+       top_field->gam_gdp_pml += src_y * fb->pitches[0];
+
+       /* input parameters */
+       top_field->gam_gdp_pmp = fb->pitches[0];
+       top_field->gam_gdp_size = clamp_val(src_h, 0, GAM_GDP_SIZE_MAX) << 16 |
+                                 clamp_val(src_w, 0, GAM_GDP_SIZE_MAX);
+
+       /* output parameters */
+       ydo = sti_vtg_get_line_number(*mode, dst_y);
+       yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1);
+       xdo = sti_vtg_get_pixel_number(*mode, dst_x);
+       xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1);
+       top_field->gam_gdp_vpo = (ydo << 16) | xdo;
+       top_field->gam_gdp_vps = (yds << 16) | xds;
+
+       /* Same content and chained together */
+       memcpy(btm_field, top_field, sizeof(*btm_field));
+       top_field->gam_gdp_nvn = list->btm_field_paddr;
+       btm_field->gam_gdp_nvn = list->top_field_paddr;
+
+       /* Interlaced mode */
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
+                                        fb->pitches[0];
+
+       if (first_prepare) {
+               /* Register gdp callback */
+               if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ?
+                               compo->vtg_main : compo->vtg_aux,
+                               &gdp->vtg_field_nb, mixer->id)) {
+                       DRM_ERROR("Cannot register VTG notifier\n");
+                       return;
+               }
+
+               /* Set and enable gdp clock */
+               if (gdp->clk_pix) {
+                       struct clk *clkp;
+                       int rate = mode->clock * 1000;
+
+                       /* According to the mixer used, the gdp pixel clock
+                        * should have a different parent clock. */
+                       if (mixer->id == STI_MIXER_MAIN)
+                               clkp = gdp->clk_main_parent;
+                       else
+                               clkp = gdp->clk_aux_parent;
+
+                       if (clkp)
+                               clk_set_parent(gdp->clk_pix, clkp);
+
+                       res = clk_set_rate(gdp->clk_pix, rate);
+                       if (res < 0) {
+                               DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
+                                         rate);
+                               return;
+                       }
+
+                       if (clk_prepare_enable(gdp->clk_pix)) {
+                               DRM_ERROR("Failed to prepare/enable gdp\n");
+                               return;
+                       }
+               }
+       }
+
+       /* Update the NVN field of the 'right' field of the current GDP node
+        * (being used by the HW) with the address of the updated ('free') top
+        * field GDP node.
+        * - In interlaced mode the 'right' field is the bottom field as we
+        *   update frames starting from their top field
+        * - In progressive mode, we update both bottom and top fields which
+        *   are equal nodes.
+        * At the next VSYNC, the updated node list will be used by the HW.
+        */
+       curr_list = sti_gdp_get_current_nodes(gdp);
+       dma_updated_top = list->top_field_paddr;
+       dma_updated_btm = list->btm_field_paddr;
+
+       dev_dbg(gdp->dev, "Current NVN:0x%X\n",
+               readl(gdp->regs + GAM_GDP_NVN_OFFSET));
+       dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n",
+               (unsigned long)cma_obj->paddr,
+               readl(gdp->regs + GAM_GDP_PML_OFFSET));
+
+       if (!curr_list) {
+               /* First update or invalid node should directly write in the
+                * hw register */
+               DRM_DEBUG_DRIVER("%s first update (or invalid node)",
+                                sti_plane_to_str(plane));
+
+               writel(gdp->is_curr_top ?
+                               dma_updated_btm : dma_updated_top,
+                               gdp->regs + GAM_GDP_NVN_OFFSET);
+               goto end;
+       }
+
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               if (gdp->is_curr_top) {
+                       /* Do not update in the middle of the frame, but
+                        * postpone the update after the bottom field has
+                        * been displayed */
+                       curr_list->btm_field->gam_gdp_nvn = dma_updated_top;
+               } else {
+                       /* Direct update to avoid one frame delay */
+                       writel(dma_updated_top,
+                              gdp->regs + GAM_GDP_NVN_OFFSET);
+               }
+       } else {
+               /* Direct update for progressive to avoid one frame delay */
+               writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET);
+       }
+
+end:
+       plane->status = STI_PLANE_UPDATED;
+}
+
+static void sti_gdp_atomic_disable(struct drm_plane *drm_plane,
+                                  struct drm_plane_state *oldstate)
+{
+       struct sti_plane *plane = to_sti_plane(drm_plane);
+       struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
+
+       if (!drm_plane->crtc) {
+               DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
+                                drm_plane->base.id);
+               return;
+       }
+
+       DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
+                        drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
+                        drm_plane->base.id, sti_plane_to_str(plane));
+
+       plane->status = STI_PLANE_DISABLING;
+}
+
+static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = {
+       .atomic_update = sti_gdp_atomic_update,
+       .atomic_disable = sti_gdp_atomic_disable,
 };
 
-struct sti_layer *sti_gdp_create(struct device *dev, int id)
+struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
+                                struct device *dev, int desc,
+                                void __iomem *baseaddr,
+                                unsigned int possible_crtcs,
+                                enum drm_plane_type type)
 {
        struct sti_gdp *gdp;
+       int res;
 
        gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL);
        if (!gdp) {
@@ -577,8 +616,33 @@ struct sti_layer *sti_gdp_create(struct device *dev, int id)
                return NULL;
        }
 
-       gdp->layer.ops = &gdp_ops;
+       gdp->dev = dev;
+       gdp->regs = baseaddr;
+       gdp->plane.desc = desc;
+       gdp->plane.status = STI_PLANE_DISABLED;
+
        gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb;
 
-       return (struct sti_layer *)gdp;
+       sti_gdp_init(gdp);
+
+       res = drm_universal_plane_init(drm_dev, &gdp->plane.drm_plane,
+                                      possible_crtcs,
+                                      &sti_plane_helpers_funcs,
+                                      gdp_supported_formats,
+                                      ARRAY_SIZE(gdp_supported_formats),
+                                      type);
+       if (res) {
+               DRM_ERROR("Failed to initialize universal plane\n");
+               goto err;
+       }
+
+       drm_plane_helper_add(&gdp->plane.drm_plane, &sti_gdp_helpers_funcs);
+
+       sti_plane_init_property(&gdp->plane, type);
+
+       return &gdp->plane.drm_plane;
+
+err:
+       devm_kfree(dev, gdp);
+       return NULL;
 }
index 1dab68274ad3e542e770d993fbacf29d9f6b38d1..73947a4a800472f9aafa02fd5da73e42fb06cff5 100644 (file)
@@ -11,6 +11,9 @@
 
 #include <linux/types.h>
 
-struct sti_layer *sti_gdp_create(struct device *dev, int id);
-
+struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
+                                struct device *dev, int desc,
+                                void __iomem *baseaddr,
+                                unsigned int possible_crtcs,
+                                enum drm_plane_type type);
 #endif
index f28a4d54487c7636fee9e1a4f5ca80ecf73adcc6..09e29e43423e21e6326b54e159ed81ffc4114b86 100644 (file)
@@ -588,7 +588,7 @@ static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
        return count;
 
 fail:
-       DRM_ERROR("Can not read HDMI EDID\n");
+       DRM_ERROR("Can't read HDMI EDID\n");
        return 0;
 }
 
@@ -693,21 +693,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
        struct sti_hdmi_connector *connector;
        struct drm_connector *drm_connector;
        struct drm_bridge *bridge;
-       struct device_node *ddc;
        int err;
 
-       ddc = of_parse_phandle(dev->of_node, "ddc", 0);
-       if (ddc) {
-               hdmi->ddc_adapt = of_find_i2c_adapter_by_node(ddc);
-               if (!hdmi->ddc_adapt) {
-                       err = -EPROBE_DEFER;
-                       of_node_put(ddc);
-                       return err;
-               }
-
-               of_node_put(ddc);
-       }
-
        /* Set the drm device handle */
        hdmi->drm_dev = drm_dev;
 
@@ -796,6 +783,7 @@ static int sti_hdmi_probe(struct platform_device *pdev)
        struct sti_hdmi *hdmi;
        struct device_node *np = dev->of_node;
        struct resource *res;
+       struct device_node *ddc;
        int ret;
 
        DRM_INFO("%s\n", __func__);
@@ -804,6 +792,17 @@ static int sti_hdmi_probe(struct platform_device *pdev)
        if (!hdmi)
                return -ENOMEM;
 
+       ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0);
+       if (ddc) {
+               hdmi->ddc_adapt = of_find_i2c_adapter_by_node(ddc);
+               if (!hdmi->ddc_adapt) {
+                       of_node_put(ddc);
+                       return -EPROBE_DEFER;
+               }
+
+               of_node_put(ddc);
+       }
+
        hdmi->dev = pdev->dev;
 
        /* Get resources */
index b0eb62de1b2ecc7d4446de5b946e972649dd725d..7c8f9b8bfae10a27339b6693b462406500639c6c 100644 (file)
 #include <linux/reset.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
 
-#include "sti_drm_plane.h"
-#include "sti_hqvdp.h"
+#include "sti_compositor.h"
 #include "sti_hqvdp_lut.h"
-#include "sti_layer.h"
+#include "sti_plane.h"
 #include "sti_vtg.h"
 
 /* Firmware name */
@@ -322,8 +323,7 @@ struct sti_hqvdp_cmd {
  * @dev:               driver device
  * @drm_dev:           the drm device
  * @regs:              registers
- * @layer:             layer structure for hqvdp it self
- * @vid_plane:         VID plug used as link with compositor IP
+ * @plane:             plane structure for hqvdp it self
  * @clk:               IP clock
  * @clk_pix_main:      pix main clock
  * @reset:             reset control
@@ -334,13 +334,13 @@ struct sti_hqvdp_cmd {
  * @hqvdp_cmd:         buffer of commands
  * @hqvdp_cmd_paddr:   physical address of hqvdp_cmd
  * @vtg:               vtg for main data path
+ * @xp70_initialized:  true if xp70 is already initialized
  */
 struct sti_hqvdp {
        struct device *dev;
        struct drm_device *drm_dev;
        void __iomem *regs;
-       struct sti_layer layer;
-       struct drm_plane *vid_plane;
+       struct sti_plane plane;
        struct clk *clk;
        struct clk *clk_pix_main;
        struct reset_control *reset;
@@ -351,24 +351,15 @@ struct sti_hqvdp {
        void *hqvdp_cmd;
        dma_addr_t hqvdp_cmd_paddr;
        struct sti_vtg *vtg;
+       bool xp70_initialized;
 };
 
-#define to_sti_hqvdp(x) container_of(x, struct sti_hqvdp, layer)
+#define to_sti_hqvdp(x) container_of(x, struct sti_hqvdp, plane)
 
 static const uint32_t hqvdp_supported_formats[] = {
        DRM_FORMAT_NV12,
 };
 
-static const uint32_t *sti_hqvdp_get_formats(struct sti_layer *layer)
-{
-       return hqvdp_supported_formats;
-}
-
-static unsigned int sti_hqvdp_get_nb_formats(struct sti_layer *layer)
-{
-       return ARRAY_SIZE(hqvdp_supported_formats);
-}
-
 /**
  * sti_hqvdp_get_free_cmd
  * @hqvdp: hqvdp structure
@@ -484,7 +475,12 @@ static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale,
 
 /**
  * sti_hqvdp_check_hw_scaling
- * @layer: hqvdp layer
+ * @hqvdp: hqvdp pointer
+ * @mode: display mode with timing constraints
+ * @src_w: source width
+ * @src_h: source height
+ * @dst_w: destination width
+ * @dst_h: destination height
  *
  * Check if the HW is able to perform the scaling request
  * The firmware scaling limitation is "CEIL(1/Zy) <= FLOOR(LFW)" where:
@@ -498,184 +494,36 @@ static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale,
  * RETURNS:
  * True if the HW can scale.
  */
-static bool sti_hqvdp_check_hw_scaling(struct sti_layer *layer)
+static bool sti_hqvdp_check_hw_scaling(struct sti_hqvdp *hqvdp,
+                                      struct drm_display_mode *mode,
+                                      int src_w, int src_h,
+                                      int dst_w, int dst_h)
 {
-       struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer);
        unsigned long lfw;
        unsigned int inv_zy;
 
-       lfw = layer->mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000);
-       lfw /= max(layer->src_w, layer->dst_w) * layer->mode->clock / 1000;
+       lfw = mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000);
+       lfw /= max(src_w, dst_w) * mode->clock / 1000;
 
-       inv_zy = DIV_ROUND_UP(layer->src_h, layer->dst_h);
+       inv_zy = DIV_ROUND_UP(src_h, dst_h);
 
        return (inv_zy <= lfw) ? true : false;
 }
 
 /**
- * sti_hqvdp_prepare_layer
- * @layer: hqvdp layer
- * @first_prepare: true if it is the first time this function is called
+ * sti_hqvdp_disable
+ * @hqvdp: hqvdp pointer
  *
- * Prepares a command for the firmware
- *
- * RETURNS:
- * 0 on success.
+ * Disables the HQVDP plane
  */
-static int sti_hqvdp_prepare_layer(struct sti_layer *layer, bool first_prepare)
-{
-       struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer);
-       struct sti_hqvdp_cmd *cmd;
-       int scale_h, scale_v;
-       int cmd_offset;
-
-       dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_layer_to_str(layer));
-
-       /* prepare and commit VID plane */
-       hqvdp->vid_plane->funcs->update_plane(hqvdp->vid_plane,
-                                       layer->crtc, layer->fb,
-                                       layer->dst_x, layer->dst_y,
-                                       layer->dst_w, layer->dst_h,
-                                       layer->src_x, layer->src_y,
-                                       layer->src_w, layer->src_h);
-
-       cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
-       if (cmd_offset == -1) {
-               DRM_ERROR("No available hqvdp_cmd now\n");
-               return -EBUSY;
-       }
-       cmd = hqvdp->hqvdp_cmd + cmd_offset;
-
-       if (!sti_hqvdp_check_hw_scaling(layer)) {
-               DRM_ERROR("Scaling beyond HW capabilities\n");
-               return -EINVAL;
-       }
-
-       /* Static parameters, defaulting to progressive mode */
-       cmd->top.config = TOP_CONFIG_PROGRESSIVE;
-       cmd->top.mem_format = TOP_MEM_FORMAT_DFLT;
-       cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT;
-       cmd->csdi.config = CSDI_CONFIG_PROG;
-
-       /* VC1RE, FMD bypassed : keep everything set to 0
-        * IQI/P2I bypassed */
-       cmd->iqi.config = IQI_CONFIG_DFLT;
-       cmd->iqi.con_bri = IQI_CON_BRI_DFLT;
-       cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT;
-       cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT;
-
-       /* Buffer planes address */
-       cmd->top.current_luma = (u32) layer->paddr + layer->offsets[0];
-       cmd->top.current_chroma = (u32) layer->paddr + layer->offsets[1];
-
-       /* Pitches */
-       cmd->top.luma_processed_pitch = cmd->top.luma_src_pitch =
-                       layer->pitches[0];
-       cmd->top.chroma_processed_pitch = cmd->top.chroma_src_pitch =
-                       layer->pitches[1];
-
-       /* Input / output size
-        * Align to upper even value */
-       layer->dst_w = ALIGN(layer->dst_w, 2);
-       layer->dst_h = ALIGN(layer->dst_h, 2);
-
-       if ((layer->src_w > MAX_WIDTH) || (layer->src_w < MIN_WIDTH) ||
-           (layer->src_h > MAX_HEIGHT) || (layer->src_h < MIN_HEIGHT) ||
-           (layer->dst_w > MAX_WIDTH) || (layer->dst_w < MIN_WIDTH) ||
-           (layer->dst_h > MAX_HEIGHT) || (layer->dst_h < MIN_HEIGHT)) {
-               DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n",
-                               layer->src_w, layer->src_h,
-                               layer->dst_w, layer->dst_h);
-               return -EINVAL;
-       }
-       cmd->top.input_viewport_size = cmd->top.input_frame_size =
-                       layer->src_h << 16 | layer->src_w;
-       cmd->hvsrc.output_picture_size = layer->dst_h << 16 | layer->dst_w;
-       cmd->top.input_viewport_ori = layer->src_y << 16 | layer->src_x;
-
-       /* Handle interlaced */
-       if (layer->fb->flags & DRM_MODE_FB_INTERLACED) {
-               /* Top field to display */
-               cmd->top.config = TOP_CONFIG_INTER_TOP;
-
-               /* Update pitches and vert size */
-               cmd->top.input_frame_size = (layer->src_h / 2) << 16 |
-                                            layer->src_w;
-               cmd->top.luma_processed_pitch *= 2;
-               cmd->top.luma_src_pitch *= 2;
-               cmd->top.chroma_processed_pitch *= 2;
-               cmd->top.chroma_src_pitch *= 2;
-
-               /* Enable directional deinterlacing processing */
-               cmd->csdi.config = CSDI_CONFIG_INTER_DIR;
-               cmd->csdi.config2 = CSDI_CONFIG2_DFLT;
-               cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT;
-       }
-
-       /* Update hvsrc lut coef */
-       scale_h = SCALE_FACTOR * layer->dst_w / layer->src_w;
-       sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc);
-
-       scale_v = SCALE_FACTOR * layer->dst_h / layer->src_h;
-       sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
-
-       if (first_prepare) {
-               /* Prevent VTG shutdown */
-               if (clk_prepare_enable(hqvdp->clk_pix_main)) {
-                       DRM_ERROR("Failed to prepare/enable pix main clk\n");
-                       return -ENXIO;
-               }
-
-               /* Register VTG Vsync callback to handle bottom fields */
-               if ((layer->fb->flags & DRM_MODE_FB_INTERLACED) &&
-                               sti_vtg_register_client(hqvdp->vtg,
-                                       &hqvdp->vtg_nb, layer->mixer_id)) {
-                       DRM_ERROR("Cannot register VTG notifier\n");
-                       return -ENXIO;
-               }
-       }
-
-       return 0;
-}
-
-static int sti_hqvdp_commit_layer(struct sti_layer *layer)
+static void sti_hqvdp_disable(struct sti_hqvdp *hqvdp)
 {
-       struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer);
-       int cmd_offset;
-
-       dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_layer_to_str(layer));
-
-       cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
-       if (cmd_offset == -1) {
-               DRM_ERROR("No available hqvdp_cmd now\n");
-               return -EBUSY;
-       }
-
-       writel(hqvdp->hqvdp_cmd_paddr + cmd_offset,
-                       hqvdp->regs + HQVDP_MBX_NEXT_CMD);
-
-       hqvdp->curr_field_count++;
-
-       /* Interlaced : get ready to display the bottom field at next Vsync */
-       if (layer->fb->flags & DRM_MODE_FB_INTERLACED)
-               hqvdp->btm_field_pending = true;
-
-       dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n",
-                       __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset);
-
-       return 0;
-}
-
-static int sti_hqvdp_disable_layer(struct sti_layer *layer)
-{
-       struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer);
        int i;
 
-       DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer));
+       DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&hqvdp->plane));
 
        /* Unregister VTG Vsync callback */
-       if ((layer->fb->flags & DRM_MODE_FB_INTERLACED) &&
-               sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb))
+       if (sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb))
                DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
 
        /* Set next cmd to NULL */
@@ -691,15 +539,10 @@ static int sti_hqvdp_disable_layer(struct sti_layer *layer)
        /* VTG can stop now */
        clk_disable_unprepare(hqvdp->clk_pix_main);
 
-       if (i == POLL_MAX_ATTEMPT) {
+       if (i == POLL_MAX_ATTEMPT)
                DRM_ERROR("XP70 could not revert to idle\n");
-               return -ENXIO;
-       }
-
-       /* disable VID plane */
-       hqvdp->vid_plane->funcs->disable_plane(hqvdp->vid_plane);
 
-       return 0;
+       hqvdp->plane.status = STI_PLANE_DISABLED;
 }
 
 /**
@@ -724,6 +567,14 @@ int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
                return 0;
        }
 
+       if (hqvdp->plane.status == STI_PLANE_FLUSHING) {
+               /* disable need to be synchronize on vsync event */
+               DRM_DEBUG_DRIVER("Vsync event received => disable %s\n",
+                                sti_plane_to_str(&hqvdp->plane));
+
+               sti_hqvdp_disable(hqvdp);
+       }
+
        if (hqvdp->btm_field_pending) {
                /* Create the btm field command from the current one */
                btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
@@ -758,32 +609,10 @@ int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
        return 0;
 }
 
-static struct drm_plane *sti_hqvdp_find_vid(struct drm_device *dev, int id)
+static void sti_hqvdp_init(struct sti_hqvdp *hqvdp)
 {
-       struct drm_plane *plane;
-
-       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-               struct sti_layer *layer = to_sti_layer(plane);
-
-               if (layer->desc == id)
-                       return plane;
-       }
-
-       return NULL;
-}
-
-static void sti_hqvd_init(struct sti_layer *layer)
-{
-       struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer);
        int size;
 
-       /* find the plane macthing with vid 0 */
-       hqvdp->vid_plane = sti_hqvdp_find_vid(hqvdp->drm_dev, STI_VID_0);
-       if (!hqvdp->vid_plane) {
-               DRM_ERROR("Cannot find Main video layer\n");
-               return;
-       }
-
        hqvdp->vtg_nb.notifier_call = sti_hqvdp_vtg_cb;
 
        /* Allocate memory for the VDP commands */
@@ -799,24 +628,213 @@ static void sti_hqvd_init(struct sti_layer *layer)
        memset(hqvdp->hqvdp_cmd, 0, size);
 }
 
-static const struct sti_layer_funcs hqvdp_ops = {
-       .get_formats = sti_hqvdp_get_formats,
-       .get_nb_formats = sti_hqvdp_get_nb_formats,
-       .init = sti_hqvd_init,
-       .prepare = sti_hqvdp_prepare_layer,
-       .commit = sti_hqvdp_commit_layer,
-       .disable = sti_hqvdp_disable_layer,
+static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
+                                   struct drm_plane_state *oldstate)
+{
+       struct drm_plane_state *state = drm_plane->state;
+       struct sti_plane *plane = to_sti_plane(drm_plane);
+       struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
+       struct drm_crtc *crtc = state->crtc;
+       struct sti_mixer *mixer = to_sti_mixer(crtc);
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_display_mode *mode = &crtc->mode;
+       int dst_x = state->crtc_x;
+       int dst_y = state->crtc_y;
+       int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
+       int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+       /* src_x are in 16.16 format */
+       int src_x = state->src_x >> 16;
+       int src_y = state->src_y >> 16;
+       int src_w = state->src_w >> 16;
+       int src_h = state->src_h >> 16;
+       bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
+       struct drm_gem_cma_object *cma_obj;
+       struct sti_hqvdp_cmd *cmd;
+       int scale_h, scale_v;
+       int cmd_offset;
+
+       DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
+                     crtc->base.id, sti_mixer_to_str(mixer),
+                     drm_plane->base.id, sti_plane_to_str(plane));
+       DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
+                     sti_plane_to_str(plane),
+                     dst_w, dst_h, dst_x, dst_y,
+                     src_w, src_h, src_x, src_y);
+
+       cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
+       if (cmd_offset == -1) {
+               DRM_ERROR("No available hqvdp_cmd now\n");
+               return;
+       }
+       cmd = hqvdp->hqvdp_cmd + cmd_offset;
+
+       if (!sti_hqvdp_check_hw_scaling(hqvdp, mode,
+                                       src_w, src_h,
+                                       dst_w, dst_h)) {
+               DRM_ERROR("Scaling beyond HW capabilities\n");
+               return;
+       }
+
+       /* Static parameters, defaulting to progressive mode */
+       cmd->top.config = TOP_CONFIG_PROGRESSIVE;
+       cmd->top.mem_format = TOP_MEM_FORMAT_DFLT;
+       cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT;
+       cmd->csdi.config = CSDI_CONFIG_PROG;
+
+       /* VC1RE, FMD bypassed : keep everything set to 0
+        * IQI/P2I bypassed */
+       cmd->iqi.config = IQI_CONFIG_DFLT;
+       cmd->iqi.con_bri = IQI_CON_BRI_DFLT;
+       cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT;
+       cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT;
+
+       cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+       if (!cma_obj) {
+               DRM_ERROR("Can't get CMA GEM object for fb\n");
+               return;
+       }
+
+       DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
+                        (char *)&fb->pixel_format,
+                        (unsigned long)cma_obj->paddr);
+
+       /* Buffer planes address */
+       cmd->top.current_luma = (u32)cma_obj->paddr + fb->offsets[0];
+       cmd->top.current_chroma = (u32)cma_obj->paddr + fb->offsets[1];
+
+       /* Pitches */
+       cmd->top.luma_processed_pitch = fb->pitches[0];
+       cmd->top.luma_src_pitch = fb->pitches[0];
+       cmd->top.chroma_processed_pitch = fb->pitches[1];
+       cmd->top.chroma_src_pitch = fb->pitches[1];
+
+       /* Input / output size
+        * Align to upper even value */
+       dst_w = ALIGN(dst_w, 2);
+       dst_h = ALIGN(dst_h, 2);
+
+       if ((src_w > MAX_WIDTH) || (src_w < MIN_WIDTH) ||
+           (src_h > MAX_HEIGHT) || (src_h < MIN_HEIGHT) ||
+           (dst_w > MAX_WIDTH) || (dst_w < MIN_WIDTH) ||
+           (dst_h > MAX_HEIGHT) || (dst_h < MIN_HEIGHT)) {
+               DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n",
+                         src_w, src_h,
+                         dst_w, dst_h);
+               return;
+       }
+
+       cmd->top.input_viewport_size = src_h << 16 | src_w;
+       cmd->top.input_frame_size = src_h << 16 | src_w;
+       cmd->hvsrc.output_picture_size = dst_h << 16 | dst_w;
+       cmd->top.input_viewport_ori = src_y << 16 | src_x;
+
+       /* Handle interlaced */
+       if (fb->flags & DRM_MODE_FB_INTERLACED) {
+               /* Top field to display */
+               cmd->top.config = TOP_CONFIG_INTER_TOP;
+
+               /* Update pitches and vert size */
+               cmd->top.input_frame_size = (src_h / 2) << 16 | src_w;
+               cmd->top.luma_processed_pitch *= 2;
+               cmd->top.luma_src_pitch *= 2;
+               cmd->top.chroma_processed_pitch *= 2;
+               cmd->top.chroma_src_pitch *= 2;
+
+               /* Enable directional deinterlacing processing */
+               cmd->csdi.config = CSDI_CONFIG_INTER_DIR;
+               cmd->csdi.config2 = CSDI_CONFIG2_DFLT;
+               cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT;
+       }
+
+       /* Update hvsrc lut coef */
+       scale_h = SCALE_FACTOR * dst_w / src_w;
+       sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc);
+
+       scale_v = SCALE_FACTOR * dst_h / src_h;
+       sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
+
+       if (first_prepare) {
+               /* Prevent VTG shutdown */
+               if (clk_prepare_enable(hqvdp->clk_pix_main)) {
+                       DRM_ERROR("Failed to prepare/enable pix main clk\n");
+                       return;
+               }
+
+               /* Register VTG Vsync callback to handle bottom fields */
+               if (sti_vtg_register_client(hqvdp->vtg,
+                                           &hqvdp->vtg_nb,
+                                           mixer->id)) {
+                       DRM_ERROR("Cannot register VTG notifier\n");
+                       return;
+               }
+       }
+
+       writel(hqvdp->hqvdp_cmd_paddr + cmd_offset,
+              hqvdp->regs + HQVDP_MBX_NEXT_CMD);
+
+       hqvdp->curr_field_count++;
+
+       /* Interlaced : get ready to display the bottom field at next Vsync */
+       if (fb->flags & DRM_MODE_FB_INTERLACED)
+               hqvdp->btm_field_pending = true;
+
+       dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n",
+               __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset);
+
+       plane->status = STI_PLANE_UPDATED;
+}
+
+static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane,
+                                    struct drm_plane_state *oldstate)
+{
+       struct sti_plane *plane = to_sti_plane(drm_plane);
+       struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
+
+       if (!drm_plane->crtc) {
+               DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
+                                drm_plane->base.id);
+               return;
+       }
+
+       DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
+                        drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
+                        drm_plane->base.id, sti_plane_to_str(plane));
+
+       plane->status = STI_PLANE_DISABLING;
+}
+
+static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = {
+       .atomic_update = sti_hqvdp_atomic_update,
+       .atomic_disable = sti_hqvdp_atomic_disable,
 };
 
-struct sti_layer *sti_hqvdp_create(struct device *dev)
+static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
+                                         struct device *dev, int desc)
 {
        struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
+       int res;
+
+       hqvdp->plane.desc = desc;
+       hqvdp->plane.status = STI_PLANE_DISABLED;
 
-       hqvdp->layer.ops = &hqvdp_ops;
+       sti_hqvdp_init(hqvdp);
 
-       return &hqvdp->layer;
+       res = drm_universal_plane_init(drm_dev, &hqvdp->plane.drm_plane, 1,
+                                      &sti_plane_helpers_funcs,
+                                      hqvdp_supported_formats,
+                                      ARRAY_SIZE(hqvdp_supported_formats),
+                                      DRM_PLANE_TYPE_OVERLAY);
+       if (res) {
+               DRM_ERROR("Failed to initialize universal plane\n");
+               return NULL;
+       }
+
+       drm_plane_helper_add(&hqvdp->plane.drm_plane, &sti_hqvdp_helpers_funcs);
+
+       sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY);
+
+       return &hqvdp->plane.drm_plane;
 }
-EXPORT_SYMBOL(sti_hqvdp_create);
 
 static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp)
 {
@@ -859,6 +877,12 @@ static void sti_hqvdp_start_xp70(const struct firmware *firmware, void *ctxt)
        } *header;
 
        DRM_DEBUG_DRIVER("\n");
+
+       if (hqvdp->xp70_initialized) {
+               DRM_INFO("HQVDP XP70 already initialized\n");
+               return;
+       }
+
        /* Check firmware parts */
        if (!firmware) {
                DRM_ERROR("Firmware not available\n");
@@ -946,7 +970,10 @@ static void sti_hqvdp_start_xp70(const struct firmware *firmware, void *ctxt)
        /* Launch Vsync */
        writel(SOFT_VSYNC_HW, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC);
 
-       DRM_INFO("HQVDP XP70 started\n");
+       DRM_INFO("HQVDP XP70 initialized\n");
+
+       hqvdp->xp70_initialized = true;
+
 out:
        release_firmware(firmware);
 }
@@ -955,7 +982,7 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
 {
        struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
-       struct sti_layer *layer;
+       struct drm_plane *plane;
        int err;
 
        DRM_DEBUG_DRIVER("\n");
@@ -971,13 +998,10 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
                return err;
        }
 
-       layer = sti_layer_create(hqvdp->dev, STI_HQVDP_0, hqvdp->regs);
-       if (!layer) {
+       /* Create HQVDP plane once xp70 is initialized */
+       plane = sti_hqvdp_create(drm_dev, hqvdp->dev, STI_HQVDP_0);
+       if (!plane)
                DRM_ERROR("Can't create HQVDP plane\n");
-               return -ENOMEM;
-       }
-
-       sti_drm_plane_init(drm_dev, layer, 1, DRM_PLANE_TYPE_OVERLAY);
 
        return 0;
 }
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.h b/drivers/gpu/drm/sti/sti_hqvdp.h
deleted file mode 100644 (file)
index cd5ecd0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics SA 2014
- * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
- * License terms:  GNU General Public License (GPL), version 2
- */
-
-#ifndef _STI_HQVDP_H_
-#define _STI_HQVDP_H_
-
-struct sti_layer *sti_hqvdp_create(struct device *dev);
-
-#endif
diff --git a/drivers/gpu/drm/sti/sti_layer.c b/drivers/gpu/drm/sti/sti_layer.c
deleted file mode 100644 (file)
index 899104f..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics SA 2014
- * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
- *          Fabien Dessenne <fabien.dessenne@st.com>
- *          for STMicroelectronics.
- * License terms:  GNU General Public License (GPL), version 2
- */
-
-#include <drm/drmP.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "sti_compositor.h"
-#include "sti_cursor.h"
-#include "sti_gdp.h"
-#include "sti_hqvdp.h"
-#include "sti_layer.h"
-#include "sti_vid.h"
-
-const char *sti_layer_to_str(struct sti_layer *layer)
-{
-       switch (layer->desc) {
-       case STI_GDP_0:
-               return "GDP0";
-       case STI_GDP_1:
-               return "GDP1";
-       case STI_GDP_2:
-               return "GDP2";
-       case STI_GDP_3:
-               return "GDP3";
-       case STI_VID_0:
-               return "VID0";
-       case STI_VID_1:
-               return "VID1";
-       case STI_CURSOR:
-               return "CURSOR";
-       case STI_HQVDP_0:
-               return "HQVDP0";
-       default:
-               return "<UNKNOWN LAYER>";
-       }
-}
-EXPORT_SYMBOL(sti_layer_to_str);
-
-struct sti_layer *sti_layer_create(struct device *dev, int desc,
-                                  void __iomem *baseaddr)
-{
-
-       struct sti_layer *layer = NULL;
-
-       switch (desc & STI_LAYER_TYPE_MASK) {
-       case STI_GDP:
-               layer = sti_gdp_create(dev, desc);
-               break;
-       case STI_VID:
-               layer = sti_vid_create(dev);
-               break;
-       case STI_CUR:
-               layer = sti_cursor_create(dev);
-               break;
-       case STI_VDP:
-               layer = sti_hqvdp_create(dev);
-               break;
-       }
-
-       if (!layer) {
-               DRM_ERROR("Failed to create layer\n");
-               return NULL;
-       }
-
-       layer->desc = desc;
-       layer->dev = dev;
-       layer->regs = baseaddr;
-
-       layer->ops->init(layer);
-
-       DRM_DEBUG_DRIVER("%s created\n", sti_layer_to_str(layer));
-
-       return layer;
-}
-EXPORT_SYMBOL(sti_layer_create);
-
-int sti_layer_prepare(struct sti_layer *layer,
-                     struct drm_crtc *crtc,
-                     struct drm_framebuffer *fb,
-                     struct drm_display_mode *mode, int mixer_id,
-                     int dest_x, int dest_y, int dest_w, int dest_h,
-                     int src_x, int src_y, int src_w, int src_h)
-{
-       int ret;
-       unsigned int i;
-       struct drm_gem_cma_object *cma_obj;
-
-       if (!layer || !fb || !mode) {
-               DRM_ERROR("Null fb, layer or mode\n");
-               return 1;
-       }
-
-       cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
-       if (!cma_obj) {
-               DRM_ERROR("Can't get CMA GEM object for fb\n");
-               return 1;
-       }
-
-       layer->crtc = crtc;
-       layer->fb = fb;
-       layer->mode = mode;
-       layer->mixer_id = mixer_id;
-       layer->dst_x = dest_x;
-       layer->dst_y = dest_y;
-       layer->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x);
-       layer->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y);
-       layer->src_x = src_x;
-       layer->src_y = src_y;
-       layer->src_w = src_w;
-       layer->src_h = src_h;
-       layer->format = fb->pixel_format;
-       layer->vaddr = cma_obj->vaddr;
-       layer->paddr = cma_obj->paddr;
-       for (i = 0; i < 4; i++) {
-               layer->pitches[i] = fb->pitches[i];
-               layer->offsets[i] = fb->offsets[i];
-       }
-
-       DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n",
-                        sti_layer_to_str(layer),
-                        layer->mixer_id);
-       DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
-                        sti_layer_to_str(layer),
-                        layer->dst_w, layer->dst_h, layer->dst_x, layer->dst_y,
-                        layer->src_w, layer->src_h, layer->src_x,
-                        layer->src_y);
-
-       DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
-                        (char *)&layer->format, (unsigned long)layer->paddr);
-
-       if (!layer->ops->prepare)
-               goto err_no_prepare;
-
-       ret = layer->ops->prepare(layer, !layer->enabled);
-       if (!ret)
-               layer->enabled = true;
-
-       return ret;
-
-err_no_prepare:
-       DRM_ERROR("Cannot prepare\n");
-       return 1;
-}
-
-int sti_layer_commit(struct sti_layer *layer)
-{
-       if (!layer)
-               return 1;
-
-       if (!layer->ops->commit)
-               goto err_no_commit;
-
-       return layer->ops->commit(layer);
-
-err_no_commit:
-       DRM_ERROR("Cannot commit\n");
-       return 1;
-}
-
-int sti_layer_disable(struct sti_layer *layer)
-{
-       int ret;
-
-       DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer));
-       if (!layer)
-               return 1;
-
-       if (!layer->enabled)
-               return 0;
-
-       if (!layer->ops->disable)
-               goto err_no_disable;
-
-       ret = layer->ops->disable(layer);
-       if (!ret)
-               layer->enabled = false;
-       else
-               DRM_ERROR("Disable failed\n");
-
-       return ret;
-
-err_no_disable:
-       DRM_ERROR("Cannot disable\n");
-       return 1;
-}
-
-const uint32_t *sti_layer_get_formats(struct sti_layer *layer)
-{
-       if (!layer)
-               return NULL;
-
-       if (!layer->ops->get_formats)
-               return NULL;
-
-       return layer->ops->get_formats(layer);
-}
-
-unsigned int sti_layer_get_nb_formats(struct sti_layer *layer)
-{
-       if (!layer)
-               return 0;
-
-       if (!layer->ops->get_nb_formats)
-               return 0;
-
-       return layer->ops->get_nb_formats(layer);
-}
diff --git a/drivers/gpu/drm/sti/sti_layer.h b/drivers/gpu/drm/sti/sti_layer.h
deleted file mode 100644 (file)
index ceff497..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics SA 2014
- * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
- *          Fabien Dessenne <fabien.dessenne@st.com>
- *          for STMicroelectronics.
- * License terms:  GNU General Public License (GPL), version 2
- */
-
-#ifndef _STI_LAYER_H_
-#define _STI_LAYER_H_
-
-#include <drm/drmP.h>
-
-#define to_sti_layer(x) container_of(x, struct sti_layer, plane)
-
-#define STI_LAYER_TYPE_SHIFT 8
-#define STI_LAYER_TYPE_MASK (~((1<<STI_LAYER_TYPE_SHIFT)-1))
-
-struct sti_layer;
-
-enum sti_layer_type {
-       STI_GDP = 1 << STI_LAYER_TYPE_SHIFT,
-       STI_VID = 2 << STI_LAYER_TYPE_SHIFT,
-       STI_CUR = 3 << STI_LAYER_TYPE_SHIFT,
-       STI_BCK = 4 << STI_LAYER_TYPE_SHIFT,
-       STI_VDP = 5 << STI_LAYER_TYPE_SHIFT
-};
-
-enum sti_layer_id_of_type {
-       STI_ID_0 = 0,
-       STI_ID_1 = 1,
-       STI_ID_2 = 2,
-       STI_ID_3 = 3
-};
-
-enum sti_layer_desc {
-       STI_GDP_0       = STI_GDP | STI_ID_0,
-       STI_GDP_1       = STI_GDP | STI_ID_1,
-       STI_GDP_2       = STI_GDP | STI_ID_2,
-       STI_GDP_3       = STI_GDP | STI_ID_3,
-       STI_VID_0       = STI_VID | STI_ID_0,
-       STI_VID_1       = STI_VID | STI_ID_1,
-       STI_HQVDP_0     = STI_VDP | STI_ID_0,
-       STI_CURSOR      = STI_CUR,
-       STI_BACK        = STI_BCK
-};
-
-/**
- * STI layer functions structure
- *
- * @get_formats:       get layer supported formats
- * @get_nb_formats:    get number of format supported
- * @init:               initialize the layer
- * @prepare:           prepare layer before rendering
- * @commit:            set layer for rendering
- * @disable:           disable layer
- */
-struct sti_layer_funcs {
-       const uint32_t* (*get_formats)(struct sti_layer *layer);
-       unsigned int (*get_nb_formats)(struct sti_layer *layer);
-       void (*init)(struct sti_layer *layer);
-       int (*prepare)(struct sti_layer *layer, bool first_prepare);
-       int (*commit)(struct sti_layer *layer);
-       int (*disable)(struct sti_layer *layer);
-};
-
-/**
- * STI layer structure
- *
- * @plane:              drm plane it is bound to (if any)
- * @fb:                 drm fb it is bound to
- * @crtc:               crtc it is bound to
- * @mode:               display mode
- * @desc:               layer type & id
- * @device:            driver device
- * @regs:              layer registers
- * @ops:                layer functions
- * @zorder:             layer z-order
- * @mixer_id:           id of the mixer used to display the layer
- * @enabled:            to know if the layer is active or not
- * @src_x src_y:        coordinates of the input (fb) area
- * @src_w src_h:        size of the input (fb) area
- * @dst_x dst_y:        coordinates of the output (crtc) area
- * @dst_w dst_h:        size of the output (crtc) area
- * @format:             format
- * @pitches:            pitch of 'planes' (eg: Y, U, V)
- * @offsets:            offset of 'planes'
- * @vaddr:              virtual address of the input buffer
- * @paddr:              physical address of the input buffer
- */
-struct sti_layer {
-       struct drm_plane plane;
-       struct drm_framebuffer *fb;
-       struct drm_crtc *crtc;
-       struct drm_display_mode *mode;
-       enum sti_layer_desc desc;
-       struct device *dev;
-       void __iomem *regs;
-       const struct sti_layer_funcs *ops;
-       int zorder;
-       int mixer_id;
-       bool enabled;
-       int src_x, src_y;
-       int src_w, src_h;
-       int dst_x, dst_y;
-       int dst_w, dst_h;
-       uint32_t format;
-       unsigned int pitches[4];
-       unsigned int offsets[4];
-       void *vaddr;
-       dma_addr_t paddr;
-};
-
-struct sti_layer *sti_layer_create(struct device *dev, int desc,
-                       void __iomem *baseaddr);
-int sti_layer_prepare(struct sti_layer *layer,
-                       struct drm_crtc *crtc,
-                       struct drm_framebuffer *fb,
-                       struct drm_display_mode *mode,
-                       int mixer_id,
-                       int dest_x, int dest_y,
-                       int dest_w, int dest_h,
-                       int src_x, int src_y,
-                       int src_w, int src_h);
-int sti_layer_commit(struct sti_layer *layer);
-int sti_layer_disable(struct sti_layer *layer);
-const uint32_t *sti_layer_get_formats(struct sti_layer *layer);
-unsigned int sti_layer_get_nb_formats(struct sti_layer *layer);
-const char *sti_layer_to_str(struct sti_layer *layer);
-
-#endif
index 13a4b84deab69104f82f3c341877e2e2aa6e3fbb..0182e936500427e8fd798251c6dccdd340b87495 100644 (file)
@@ -58,6 +58,7 @@ const char *sti_mixer_to_str(struct sti_mixer *mixer)
                return "<UNKNOWN MIXER>";
        }
 }
+EXPORT_SYMBOL(sti_mixer_to_str);
 
 static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
 {
@@ -101,52 +102,57 @@ static void sti_mixer_set_background_area(struct sti_mixer *mixer,
        sti_mixer_reg_write(mixer, GAM_MIXER_BCS, yds << 16 | xds);
 }
 
-int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer)
+int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane)
 {
-       int layer_id = 0, depth = layer->zorder;
+       int plane_id, depth = plane->zorder;
+       unsigned int i;
        u32 mask, val;
 
-       if (depth >= GAM_MIXER_NB_DEPTH_LEVEL)
+       if ((depth < 1) || (depth > GAM_MIXER_NB_DEPTH_LEVEL))
                return 1;
 
-       switch (layer->desc) {
+       switch (plane->desc) {
        case STI_GDP_0:
-               layer_id = GAM_DEPTH_GDP0_ID;
+               plane_id = GAM_DEPTH_GDP0_ID;
                break;
        case STI_GDP_1:
-               layer_id = GAM_DEPTH_GDP1_ID;
+               plane_id = GAM_DEPTH_GDP1_ID;
                break;
        case STI_GDP_2:
-               layer_id = GAM_DEPTH_GDP2_ID;
+               plane_id = GAM_DEPTH_GDP2_ID;
                break;
        case STI_GDP_3:
-               layer_id = GAM_DEPTH_GDP3_ID;
+               plane_id = GAM_DEPTH_GDP3_ID;
                break;
-       case STI_VID_0:
        case STI_HQVDP_0:
-               layer_id = GAM_DEPTH_VID0_ID;
-               break;
-       case STI_VID_1:
-               layer_id = GAM_DEPTH_VID1_ID;
+               plane_id = GAM_DEPTH_VID0_ID;
                break;
        case STI_CURSOR:
                /* no need to set depth for cursor */
                return 0;
        default:
-               DRM_ERROR("Unknown layer %d\n", layer->desc);
+               DRM_ERROR("Unknown plane %d\n", plane->desc);
                return 1;
        }
-       mask = GAM_DEPTH_MASK_ID << (3 * depth);
-       layer_id = layer_id << (3 * depth);
+
+       /* Search if a previous depth was already assigned to the plane */
+       val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB);
+       for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
+               mask = GAM_DEPTH_MASK_ID << (3 * i);
+               if ((val & mask) == plane_id << (3 * i))
+                       break;
+       }
+
+       mask |= GAM_DEPTH_MASK_ID << (3 * (depth - 1));
+       plane_id = plane_id << (3 * (depth - 1));
 
        DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer),
-                        sti_layer_to_str(layer), depth);
+                        sti_plane_to_str(plane), depth);
        dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n",
-               layer_id, mask);
+               plane_id, mask);
 
-       val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB);
        val &= ~mask;
-       val |= layer_id;
+       val |= plane_id;
        sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val);
 
        dev_dbg(mixer->dev, "Read GAM_MIXER_CRB 0x%x\n",
@@ -176,9 +182,9 @@ int sti_mixer_active_video_area(struct sti_mixer *mixer,
        return 0;
 }
 
-static u32 sti_mixer_get_layer_mask(struct sti_layer *layer)
+static u32 sti_mixer_get_plane_mask(struct sti_plane *plane)
 {
-       switch (layer->desc) {
+       switch (plane->desc) {
        case STI_BACK:
                return GAM_CTL_BACK_MASK;
        case STI_GDP_0:
@@ -189,11 +195,8 @@ static u32 sti_mixer_get_layer_mask(struct sti_layer *layer)
                return GAM_CTL_GDP2_MASK;
        case STI_GDP_3:
                return GAM_CTL_GDP3_MASK;
-       case STI_VID_0:
        case STI_HQVDP_0:
                return GAM_CTL_VID0_MASK;
-       case STI_VID_1:
-               return GAM_CTL_VID1_MASK;
        case STI_CURSOR:
                return GAM_CTL_CURSOR_MASK;
        default:
@@ -201,17 +204,17 @@ static u32 sti_mixer_get_layer_mask(struct sti_layer *layer)
        }
 }
 
-int sti_mixer_set_layer_status(struct sti_mixer *mixer,
-                              struct sti_layer *layer, bool status)
+int sti_mixer_set_plane_status(struct sti_mixer *mixer,
+                              struct sti_plane *plane, bool status)
 {
        u32 mask, val;
 
        DRM_DEBUG_DRIVER("%s %s %s\n", status ? "enable" : "disable",
-                        sti_mixer_to_str(mixer), sti_layer_to_str(layer));
+                        sti_mixer_to_str(mixer), sti_plane_to_str(plane));
 
-       mask = sti_mixer_get_layer_mask(layer);
+       mask = sti_mixer_get_plane_mask(plane);
        if (!mask) {
-               DRM_ERROR("Can not find layer mask\n");
+               DRM_ERROR("Can't find layer mask\n");
                return -EINVAL;
        }
 
@@ -223,15 +226,6 @@ int sti_mixer_set_layer_status(struct sti_mixer *mixer,
        return 0;
 }
 
-void sti_mixer_clear_all_layers(struct sti_mixer *mixer)
-{
-       u32 val;
-
-       DRM_DEBUG_DRIVER("%s clear all layer\n", sti_mixer_to_str(mixer));
-       val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL) & 0xFFFF0000;
-       sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
-}
-
 void sti_mixer_set_matrix(struct sti_mixer *mixer)
 {
        unsigned int i;
index b97282182908f0cf77589e3e39b94c5b977a9bed..efb1a9a5ba86b8c71bec36f7509a8373ee0cb3e0 100644 (file)
 
 #include <drm/drmP.h>
 
-#include "sti_layer.h"
+#include "sti_plane.h"
 
 #define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc)
 
+enum sti_mixer_status {
+       STI_MIXER_READY,
+       STI_MIXER_DISABLING,
+       STI_MIXER_DISABLED,
+};
+
 /**
  * STI Mixer subdevice structure
  *
  * @id: id of the mixer
  * @drm_crtc: crtc object link to the mixer
  * @pending_event: set if a flip event is pending on crtc
- * @enabled: to know if the mixer is active or not
+ * @status: to know the status of the mixer
  */
 struct sti_mixer {
        struct device *dev;
        void __iomem *regs;
        int id;
-       struct drm_crtc drm_crtc;
+       struct drm_crtc drm_crtc;
        struct drm_pending_vblank_event *pending_event;
-       bool enabled;
+       enum sti_mixer_status status;
 };
 
 const char *sti_mixer_to_str(struct sti_mixer *mixer);
 
 struct sti_mixer *sti_mixer_create(struct device *dev, int id,
-               void __iomem *baseaddr);
+                                  void __iomem *baseaddr);
 
-int sti_mixer_set_layer_status(struct sti_mixer *mixer,
-               struct sti_layer *layer, bool status);
-void sti_mixer_clear_all_layers(struct sti_mixer *mixer);
-int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer);
+int sti_mixer_set_plane_status(struct sti_mixer *mixer,
+                              struct sti_plane *plane, bool status);
+int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane);
 int sti_mixer_active_video_area(struct sti_mixer *mixer,
-               struct drm_display_mode *mode);
+                               struct drm_display_mode *mode);
 
 void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable);
 
 /* depth in Cross-bar control = z order */
-#define GAM_MIXER_NB_DEPTH_LEVEL 7
+#define GAM_MIXER_NB_DEPTH_LEVEL 6
 
 #define STI_MIXER_MAIN 0
 #define STI_MIXER_AUX  1
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c
new file mode 100644 (file)
index 0000000..d5c5e91
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2014
+ * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
+ *          Fabien Dessenne <fabien.dessenne@st.com>
+ *          for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "sti_compositor.h"
+#include "sti_drv.h"
+#include "sti_plane.h"
+
+/* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */
+enum sti_plane_desc sti_plane_default_zorder[] = {
+       STI_GDP_0,
+       STI_GDP_1,
+       STI_HQVDP_0,
+       STI_GDP_2,
+       STI_GDP_3,
+};
+
+const char *sti_plane_to_str(struct sti_plane *plane)
+{
+       switch (plane->desc) {
+       case STI_GDP_0:
+               return "GDP0";
+       case STI_GDP_1:
+               return "GDP1";
+       case STI_GDP_2:
+               return "GDP2";
+       case STI_GDP_3:
+               return "GDP3";
+       case STI_HQVDP_0:
+               return "HQVDP0";
+       case STI_CURSOR:
+               return "CURSOR";
+       default:
+               return "<UNKNOWN PLANE>";
+       }
+}
+EXPORT_SYMBOL(sti_plane_to_str);
+
+static void sti_plane_destroy(struct drm_plane *drm_plane)
+{
+       DRM_DEBUG_DRIVER("\n");
+
+       drm_plane_helper_disable(drm_plane);
+       drm_plane_cleanup(drm_plane);
+}
+
+static int sti_plane_set_property(struct drm_plane *drm_plane,
+                                 struct drm_property *property,
+                                 uint64_t val)
+{
+       struct drm_device *dev = drm_plane->dev;
+       struct sti_private *private = dev->dev_private;
+       struct sti_plane *plane = to_sti_plane(drm_plane);
+
+       DRM_DEBUG_DRIVER("\n");
+
+       if (property == private->plane_zorder_property) {
+               plane->zorder = val;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane)
+{
+       struct drm_device *dev = drm_plane->dev;
+       struct sti_private *private = dev->dev_private;
+       struct sti_plane *plane = to_sti_plane(drm_plane);
+       struct drm_property *prop;
+
+       prop = private->plane_zorder_property;
+       if (!prop) {
+               prop = drm_property_create_range(dev, 0, "zpos", 1,
+                                                GAM_MIXER_NB_DEPTH_LEVEL);
+               if (!prop)
+                       return;
+
+               private->plane_zorder_property = prop;
+       }
+
+       drm_object_attach_property(&drm_plane->base, prop, plane->zorder);
+}
+
+void sti_plane_init_property(struct sti_plane *plane,
+                            enum drm_plane_type type)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++)
+               if (sti_plane_default_zorder[i] == plane->desc)
+                       break;
+
+       plane->zorder = i + 1;
+
+       if (type == DRM_PLANE_TYPE_OVERLAY)
+               sti_plane_attach_zorder_property(&plane->drm_plane);
+
+       DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n",
+                        plane->drm_plane.base.id,
+                        sti_plane_to_str(plane), plane->zorder);
+}
+EXPORT_SYMBOL(sti_plane_init_property);
+
+struct drm_plane_funcs sti_plane_helpers_funcs = {
+       .update_plane = drm_atomic_helper_update_plane,
+       .disable_plane = drm_atomic_helper_disable_plane,
+       .destroy = sti_plane_destroy,
+       .set_property = sti_plane_set_property,
+       .reset = drm_atomic_helper_plane_reset,
+       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+EXPORT_SYMBOL(sti_plane_helpers_funcs);
diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h
new file mode 100644 (file)
index 0000000..86f1e6f
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2014
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _STI_PLANE_H_
+#define _STI_PLANE_H_
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+
+extern struct drm_plane_funcs sti_plane_helpers_funcs;
+
+#define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane)
+
+#define STI_PLANE_TYPE_SHIFT 8
+#define STI_PLANE_TYPE_MASK (~((1 << STI_PLANE_TYPE_SHIFT) - 1))
+
+enum sti_plane_type {
+       STI_GDP = 1 << STI_PLANE_TYPE_SHIFT,
+       STI_VDP = 2 << STI_PLANE_TYPE_SHIFT,
+       STI_CUR = 3 << STI_PLANE_TYPE_SHIFT,
+       STI_BCK = 4 << STI_PLANE_TYPE_SHIFT
+};
+
+enum sti_plane_id_of_type {
+       STI_ID_0 = 0,
+       STI_ID_1 = 1,
+       STI_ID_2 = 2,
+       STI_ID_3 = 3
+};
+
+enum sti_plane_desc {
+       STI_GDP_0       = STI_GDP | STI_ID_0,
+       STI_GDP_1       = STI_GDP | STI_ID_1,
+       STI_GDP_2       = STI_GDP | STI_ID_2,
+       STI_GDP_3       = STI_GDP | STI_ID_3,
+       STI_HQVDP_0     = STI_VDP | STI_ID_0,
+       STI_CURSOR      = STI_CUR,
+       STI_BACK        = STI_BCK
+};
+
+enum sti_plane_status {
+       STI_PLANE_READY,
+       STI_PLANE_UPDATED,
+       STI_PLANE_DISABLING,
+       STI_PLANE_FLUSHING,
+       STI_PLANE_DISABLED,
+};
+
+/**
+ * STI plane structure
+ *
+ * @plane:              drm plane it is bound to (if any)
+ * @desc:               plane type & id
+ * @status:             to know the status of the plane
+ * @zorder:             plane z-order
+ */
+struct sti_plane {
+       struct drm_plane drm_plane;
+       enum sti_plane_desc desc;
+       enum sti_plane_status status;
+       int zorder;
+};
+
+const char *sti_plane_to_str(struct sti_plane *plane);
+void sti_plane_init_property(struct sti_plane *plane,
+                            enum drm_plane_type type);
+#endif
index 5cc53116508ebac4ecd469b76785a4b1bd033374..c1aac8e66fb5024a626aa5a37bf99264beb0d870 100644 (file)
@@ -16,7 +16,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 
-#include "sti_drm_crtc.h"
+#include "sti_crtc.h"
 
 /* glue registers */
 #define TVO_CSC_MAIN_M0                  0x000
@@ -473,7 +473,7 @@ static void sti_dvo_encoder_commit(struct drm_encoder *encoder)
 {
        struct sti_tvout *tvout = to_sti_tvout(encoder);
 
-       tvout_dvo_start(tvout, sti_drm_crtc_is_main(encoder->crtc));
+       tvout_dvo_start(tvout, sti_crtc_is_main(encoder->crtc));
 }
 
 static void sti_dvo_encoder_disable(struct drm_encoder *encoder)
@@ -523,7 +523,7 @@ static void sti_hda_encoder_commit(struct drm_encoder *encoder)
 {
        struct sti_tvout *tvout = to_sti_tvout(encoder);
 
-       tvout_hda_start(tvout, sti_drm_crtc_is_main(encoder->crtc));
+       tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc));
 }
 
 static void sti_hda_encoder_disable(struct drm_encoder *encoder)
@@ -575,7 +575,7 @@ static void sti_hdmi_encoder_commit(struct drm_encoder *encoder)
 {
        struct sti_tvout *tvout = to_sti_tvout(encoder);
 
-       tvout_hdmi_start(tvout, sti_drm_crtc_is_main(encoder->crtc));
+       tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc));
 }
 
 static void sti_hdmi_encoder_disable(struct drm_encoder *encoder)
@@ -644,7 +644,6 @@ static int sti_tvout_bind(struct device *dev, struct device *master, void *data)
        struct sti_tvout *tvout = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
        unsigned int i;
-       int ret;
 
        tvout->drm_dev = drm_dev;
 
@@ -658,17 +657,15 @@ static int sti_tvout_bind(struct device *dev, struct device *master, void *data)
 
        sti_tvout_create_encoders(drm_dev, tvout);
 
-       ret = component_bind_all(dev, drm_dev);
-       if (ret)
-               sti_tvout_destroy_encoders(tvout);
-
-       return ret;
+       return 0;
 }
 
 static void sti_tvout_unbind(struct device *dev, struct device *master,
        void *data)
 {
-       /* do nothing */
+       struct sti_tvout *tvout = dev_get_drvdata(dev);
+
+       sti_tvout_destroy_encoders(tvout);
 }
 
 static const struct component_ops sti_tvout_ops = {
@@ -676,34 +673,12 @@ static const struct component_ops sti_tvout_ops = {
        .unbind = sti_tvout_unbind,
 };
 
-static int compare_of(struct device *dev, void *data)
-{
-       return dev->of_node == data;
-}
-
-static int sti_tvout_master_bind(struct device *dev)
-{
-       return 0;
-}
-
-static void sti_tvout_master_unbind(struct device *dev)
-{
-       /* do nothing */
-}
-
-static const struct component_master_ops sti_tvout_master_ops = {
-       .bind = sti_tvout_master_bind,
-       .unbind = sti_tvout_master_unbind,
-};
-
 static int sti_tvout_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *node = dev->of_node;
        struct sti_tvout *tvout;
        struct resource *res;
-       struct device_node *child_np;
-       struct component_match *match = NULL;
 
        DRM_INFO("%s\n", __func__);
 
@@ -734,24 +709,11 @@ static int sti_tvout_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, tvout);
 
-       of_platform_populate(node, NULL, NULL, dev);
-
-       child_np = of_get_next_available_child(node, NULL);
-
-       while (child_np) {
-               component_match_add(dev, &match, compare_of, child_np);
-               of_node_put(child_np);
-               child_np = of_get_next_available_child(node, child_np);
-       }
-
-       component_master_add_with_match(dev, &sti_tvout_master_ops, match);
-
        return component_add(dev, &sti_tvout_ops);
 }
 
 static int sti_tvout_remove(struct platform_device *pdev)
 {
-       component_master_del(&pdev->dev, &sti_tvout_master_ops);
        component_del(&pdev->dev, &sti_tvout_ops);
        return 0;
 }
index 10ced6a479f42fb8cb1235a7409ad336097894ab..a8254cc362a1eddf2e9d9516e15e2fbc7514b705 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <drm/drmP.h>
 
-#include "sti_layer.h"
+#include "sti_plane.h"
 #include "sti_vid.h"
 #include "sti_vtg.h"
 
 #define VID_MPR2_BT709          0x07150545
 #define VID_MPR3_BT709          0x00000AE8
 
-static int sti_vid_prepare_layer(struct sti_layer *vid, bool first_prepare)
+void sti_vid_commit(struct sti_vid *vid,
+                   struct drm_plane_state *state)
 {
-       u32 val;
+       struct drm_crtc *crtc = state->crtc;
+       struct drm_display_mode *mode = &crtc->mode;
+       int dst_x = state->crtc_x;
+       int dst_y = state->crtc_y;
+       int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
+       int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+       u32 val, ydo, xdo, yds, xds;
+
+       /* Input / output size
+        * Align to upper even value */
+       dst_w = ALIGN(dst_w, 2);
+       dst_h = ALIGN(dst_h, 2);
 
        /* Unmask */
        val = readl(vid->regs + VID_CTL);
        val &= ~VID_CTL_IGNORE;
        writel(val, vid->regs + VID_CTL);
 
-       return 0;
-}
-
-static int sti_vid_commit_layer(struct sti_layer *vid)
-{
-       struct drm_display_mode *mode = vid->mode;
-       u32 ydo, xdo, yds, xds;
-
-       ydo = sti_vtg_get_line_number(*mode, vid->dst_y);
-       yds = sti_vtg_get_line_number(*mode, vid->dst_y + vid->dst_h - 1);
-       xdo = sti_vtg_get_pixel_number(*mode, vid->dst_x);
-       xds = sti_vtg_get_pixel_number(*mode, vid->dst_x + vid->dst_w - 1);
+       ydo = sti_vtg_get_line_number(*mode, dst_y);
+       yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1);
+       xdo = sti_vtg_get_pixel_number(*mode, dst_x);
+       xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1);
 
        writel((ydo << 16) | xdo, vid->regs + VID_VPO);
        writel((yds << 16) | xds, vid->regs + VID_VPS);
-
-       return 0;
 }
 
-static int sti_vid_disable_layer(struct sti_layer *vid)
+void sti_vid_disable(struct sti_vid *vid)
 {
        u32 val;
 
@@ -79,21 +81,9 @@ static int sti_vid_disable_layer(struct sti_layer *vid)
        val = readl(vid->regs + VID_CTL);
        val |= VID_CTL_IGNORE;
        writel(val, vid->regs + VID_CTL);
-
-       return 0;
 }
 
-static const uint32_t *sti_vid_get_formats(struct sti_layer *layer)
-{
-       return NULL;
-}
-
-static unsigned int sti_vid_get_nb_formats(struct sti_layer *layer)
-{
-       return 0;
-}
-
-static void sti_vid_init(struct sti_layer *vid)
+static void sti_vid_init(struct sti_vid *vid)
 {
        /* Enable PSI, Mask layer */
        writel(VID_CTL_PSI_ENABLE | VID_CTL_IGNORE, vid->regs + VID_CTL);
@@ -113,18 +103,10 @@ static void sti_vid_init(struct sti_layer *vid)
        writel(VID_CSAT_DFLT, vid->regs + VID_CSAT);
 }
 
-static const struct sti_layer_funcs vid_ops = {
-       .get_formats = sti_vid_get_formats,
-       .get_nb_formats = sti_vid_get_nb_formats,
-       .init = sti_vid_init,
-       .prepare = sti_vid_prepare_layer,
-       .commit = sti_vid_commit_layer,
-       .disable = sti_vid_disable_layer,
-};
-
-struct sti_layer *sti_vid_create(struct device *dev)
+struct sti_vid *sti_vid_create(struct device *dev, int id,
+                              void __iomem *baseaddr)
 {
-       struct sti_layer *vid;
+       struct sti_vid *vid;
 
        vid = devm_kzalloc(dev, sizeof(*vid), GFP_KERNEL);
        if (!vid) {
@@ -132,7 +114,11 @@ struct sti_layer *sti_vid_create(struct device *dev)
                return NULL;
        }
 
-       vid->ops = &vid_ops;
+       vid->dev = dev;
+       vid->regs = baseaddr;
+       vid->id = id;
+
+       sti_vid_init(vid);
 
        return vid;
 }
index 2c0aecd632945011993e51e4e812483a102e1fe3..5dea4791f1d62bc04206186507987f3aa35835aa 100644 (file)
@@ -7,6 +7,23 @@
 #ifndef _STI_VID_H_
 #define _STI_VID_H_
 
-struct sti_layer *sti_vid_create(struct device *dev);
+/**
+ * STI VID structure
+ *
+ * @dev:   driver device
+ * @regs:  vid registers
+ * @id:    id of the vid
+ */
+struct sti_vid {
+       struct device *dev;
+       void __iomem *regs;
+       int id;
+};
+
+void sti_vid_commit(struct sti_vid *vid,
+                   struct drm_plane_state *state);
+void sti_vid_disable(struct sti_vid *vid);
+struct sti_vid *sti_vid_create(struct device *dev, int id,
+                              void __iomem *baseaddr);
 
 #endif
index a287e4fec8653d91e55bb2765e2379984b65bef5..ddefb85dc4f72f4ee8d1fd6aa7678d5236144eda 100644 (file)
@@ -76,6 +76,14 @@ to_tegra_plane_state(struct drm_plane_state *state)
        return NULL;
 }
 
+static void tegra_dc_stats_reset(struct tegra_dc_stats *stats)
+{
+       stats->frames = 0;
+       stats->vblank = 0;
+       stats->underflow = 0;
+       stats->overflow = 0;
+}
+
 /*
  * Reads the active copy of a register. This takes the dc->lock spinlock to
  * prevent races with the VBLANK processing which also needs access to the
@@ -759,7 +767,6 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
        /* position the cursor */
        value = (state->crtc_y & 0x3fff) << 16 | (state->crtc_x & 0x3fff);
        tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
-
 }
 
 static void tegra_cursor_atomic_disable(struct drm_plane *plane,
@@ -809,9 +816,11 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
                return ERR_PTR(-ENOMEM);
 
        /*
-        * We'll treat the cursor as an overlay plane with index 6 here so
-        * that the update and activation request bits in DC_CMD_STATE_CONTROL
-        * match up.
+        * This index is kind of fake. The cursor isn't a regular plane, but
+        * its update and activation request bits in DC_CMD_STATE_CONTROL do
+        * use the same programming. Setting this fake index here allows the
+        * code in tegra_add_plane_state() to do the right thing without the
+        * need to special-casing the cursor plane.
         */
        plane->index = 6;
 
@@ -1015,6 +1024,8 @@ static void tegra_crtc_reset(struct drm_crtc *crtc)
                crtc->state = &state->base;
                crtc->state->crtc = crtc;
        }
+
+       drm_crtc_vblank_reset(crtc);
 }
 
 static struct drm_crtc_state *
@@ -1052,90 +1063,6 @@ static const struct drm_crtc_funcs tegra_crtc_funcs = {
        .atomic_destroy_state = tegra_crtc_atomic_destroy_state,
 };
 
-static void tegra_dc_stop(struct tegra_dc *dc)
-{
-       u32 value;
-
-       /* stop the display controller */
-       value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
-       value &= ~DISP_CTRL_MODE_MASK;
-       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
-       tegra_dc_commit(dc);
-}
-
-static bool tegra_dc_idle(struct tegra_dc *dc)
-{
-       u32 value;
-
-       value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND);
-
-       return (value & DISP_CTRL_MODE_MASK) == 0;
-}
-
-static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout)
-{
-       timeout = jiffies + msecs_to_jiffies(timeout);
-
-       while (time_before(jiffies, timeout)) {
-               if (tegra_dc_idle(dc))
-                       return 0;
-
-               usleep_range(1000, 2000);
-       }
-
-       dev_dbg(dc->dev, "timeout waiting for DC to become idle\n");
-       return -ETIMEDOUT;
-}
-
-static void tegra_crtc_disable(struct drm_crtc *crtc)
-{
-       struct tegra_dc *dc = to_tegra_dc(crtc);
-       u32 value;
-
-       if (!tegra_dc_idle(dc)) {
-               tegra_dc_stop(dc);
-
-               /*
-                * Ignore the return value, there isn't anything useful to do
-                * in case this fails.
-                */
-               tegra_dc_wait_idle(dc, 100);
-       }
-
-       /*
-        * This should really be part of the RGB encoder driver, but clearing
-        * these bits has the side-effect of stopping the display controller.
-        * When that happens no VBLANK interrupts will be raised. At the same
-        * time the encoder is disabled before the display controller, so the
-        * above code is always going to timeout waiting for the controller
-        * to go idle.
-        *
-        * Given the close coupling between the RGB encoder and the display
-        * controller doing it here is still kind of okay. None of the other
-        * encoder drivers require these bits to be cleared.
-        *
-        * XXX: Perhaps given that the display controller is switched off at
-        * this point anyway maybe clearing these bits isn't even useful for
-        * the RGB encoder?
-        */
-       if (dc->rgb) {
-               value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
-               value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-                          PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
-               tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-       }
-
-       drm_crtc_vblank_off(crtc);
-}
-
-static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
-                                 const struct drm_display_mode *mode,
-                                 struct drm_display_mode *adjusted)
-{
-       return true;
-}
-
 static int tegra_dc_set_timings(struct tegra_dc *dc,
                                struct drm_display_mode *mode)
 {
@@ -1229,7 +1156,85 @@ static void tegra_dc_commit_state(struct tegra_dc *dc,
        tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
 }
 
-static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
+static void tegra_dc_stop(struct tegra_dc *dc)
+{
+       u32 value;
+
+       /* stop the display controller */
+       value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+       value &= ~DISP_CTRL_MODE_MASK;
+       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+       tegra_dc_commit(dc);
+}
+
+static bool tegra_dc_idle(struct tegra_dc *dc)
+{
+       u32 value;
+
+       value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND);
+
+       return (value & DISP_CTRL_MODE_MASK) == 0;
+}
+
+static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout)
+{
+       timeout = jiffies + msecs_to_jiffies(timeout);
+
+       while (time_before(jiffies, timeout)) {
+               if (tegra_dc_idle(dc))
+                       return 0;
+
+               usleep_range(1000, 2000);
+       }
+
+       dev_dbg(dc->dev, "timeout waiting for DC to become idle\n");
+       return -ETIMEDOUT;
+}
+
+static void tegra_crtc_disable(struct drm_crtc *crtc)
+{
+       struct tegra_dc *dc = to_tegra_dc(crtc);
+       u32 value;
+
+       if (!tegra_dc_idle(dc)) {
+               tegra_dc_stop(dc);
+
+               /*
+                * Ignore the return value, there isn't anything useful to do
+                * in case this fails.
+                */
+               tegra_dc_wait_idle(dc, 100);
+       }
+
+       /*
+        * This should really be part of the RGB encoder driver, but clearing
+        * these bits has the side-effect of stopping the display controller.
+        * When that happens no VBLANK interrupts will be raised. At the same
+        * time the encoder is disabled before the display controller, so the
+        * above code is always going to timeout waiting for the controller
+        * to go idle.
+        *
+        * Given the close coupling between the RGB encoder and the display
+        * controller doing it here is still kind of okay. None of the other
+        * encoder drivers require these bits to be cleared.
+        *
+        * XXX: Perhaps given that the display controller is switched off at
+        * this point anyway maybe clearing these bits isn't even useful for
+        * the RGB encoder?
+        */
+       if (dc->rgb) {
+               value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+               value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+                          PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
+               tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+       }
+
+       tegra_dc_stats_reset(&dc->stats);
+       drm_crtc_vblank_off(crtc);
+}
+
+static void tegra_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_display_mode *mode = &crtc->state->adjusted_mode;
        struct tegra_dc_state *state = to_dc_state(crtc->state);
@@ -1259,15 +1264,7 @@ static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
        tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
 
        tegra_dc_commit(dc);
-}
-
-static void tegra_crtc_prepare(struct drm_crtc *crtc)
-{
-       drm_crtc_vblank_off(crtc);
-}
 
-static void tegra_crtc_commit(struct drm_crtc *crtc)
-{
        drm_crtc_vblank_on(crtc);
 }
 
@@ -1277,7 +1274,8 @@ static int tegra_crtc_atomic_check(struct drm_crtc *crtc,
        return 0;
 }
 
-static void tegra_crtc_atomic_begin(struct drm_crtc *crtc)
+static void tegra_crtc_atomic_begin(struct drm_crtc *crtc,
+                                   struct drm_crtc_state *old_crtc_state)
 {
        struct tegra_dc *dc = to_tegra_dc(crtc);
 
@@ -1291,7 +1289,8 @@ static void tegra_crtc_atomic_begin(struct drm_crtc *crtc)
        }
 }
 
-static void tegra_crtc_atomic_flush(struct drm_crtc *crtc)
+static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,
+                                   struct drm_crtc_state *old_crtc_state)
 {
        struct tegra_dc_state *state = to_dc_state(crtc->state);
        struct tegra_dc *dc = to_tegra_dc(crtc);
@@ -1302,10 +1301,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_nofb = tegra_crtc_mode_set_nofb,
-       .prepare = tegra_crtc_prepare,
-       .commit = tegra_crtc_commit,
+       .enable = tegra_crtc_enable,
        .atomic_check = tegra_crtc_atomic_check,
        .atomic_begin = tegra_crtc_atomic_begin,
        .atomic_flush = tegra_crtc_atomic_flush,
@@ -1323,6 +1319,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
                /*
                dev_dbg(dc->dev, "%s(): frame end\n", __func__);
                */
+               dc->stats.frames++;
        }
 
        if (status & VBLANK_INT) {
@@ -1331,12 +1328,21 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
                */
                drm_crtc_handle_vblank(&dc->base);
                tegra_dc_finish_page_flip(dc);
+               dc->stats.vblank++;
        }
 
        if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) {
                /*
                dev_dbg(dc->dev, "%s(): underflow\n", __func__);
                */
+               dc->stats.underflow++;
+       }
+
+       if (status & (WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT)) {
+               /*
+               dev_dbg(dc->dev, "%s(): overflow\n", __func__);
+               */
+               dc->stats.overflow++;
        }
 
        return IRQ_HANDLED;
@@ -1346,6 +1352,14 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data)
 {
        struct drm_info_node *node = s->private;
        struct tegra_dc *dc = node->info_ent->data;
+       int err = 0;
+
+       drm_modeset_lock_crtc(&dc->base, NULL);
+
+       if (!dc->base.state->active) {
+               err = -EBUSY;
+               goto unlock;
+       }
 
 #define DUMP_REG(name)                                         \
        seq_printf(s, "%-40s %#05x %08x\n", #name, name,        \
@@ -1566,11 +1580,59 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data)
 
 #undef DUMP_REG
 
+unlock:
+       drm_modeset_unlock_crtc(&dc->base);
+       return err;
+}
+
+static int tegra_dc_show_crc(struct seq_file *s, void *data)
+{
+       struct drm_info_node *node = s->private;
+       struct tegra_dc *dc = node->info_ent->data;
+       int err = 0;
+       u32 value;
+
+       drm_modeset_lock_crtc(&dc->base, NULL);
+
+       if (!dc->base.state->active) {
+               err = -EBUSY;
+               goto unlock;
+       }
+
+       value = DC_COM_CRC_CONTROL_ACTIVE_DATA | DC_COM_CRC_CONTROL_ENABLE;
+       tegra_dc_writel(dc, value, DC_COM_CRC_CONTROL);
+       tegra_dc_commit(dc);
+
+       drm_crtc_wait_one_vblank(&dc->base);
+       drm_crtc_wait_one_vblank(&dc->base);
+
+       value = tegra_dc_readl(dc, DC_COM_CRC_CHECKSUM);
+       seq_printf(s, "%08x\n", value);
+
+       tegra_dc_writel(dc, 0, DC_COM_CRC_CONTROL);
+
+unlock:
+       drm_modeset_unlock_crtc(&dc->base);
+       return err;
+}
+
+static int tegra_dc_show_stats(struct seq_file *s, void *data)
+{
+       struct drm_info_node *node = s->private;
+       struct tegra_dc *dc = node->info_ent->data;
+
+       seq_printf(s, "frames: %lu\n", dc->stats.frames);
+       seq_printf(s, "vblank: %lu\n", dc->stats.vblank);
+       seq_printf(s, "underflow: %lu\n", dc->stats.underflow);
+       seq_printf(s, "overflow: %lu\n", dc->stats.overflow);
+
        return 0;
 }
 
 static struct drm_info_list debugfs_files[] = {
        { "regs", tegra_dc_show_regs, 0, NULL },
+       { "crc", tegra_dc_show_crc, 0, NULL },
+       { "stats", tegra_dc_show_stats, 0, NULL },
 };
 
 static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor)
@@ -1716,7 +1778,8 @@ static int tegra_dc_init(struct host1x_client *client)
                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;
+       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
+               WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
        tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
 
        value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
@@ -1732,15 +1795,19 @@ static int tegra_dc_init(struct host1x_client *client)
                WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
        tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
 
-       value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
+       value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
+               WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
        tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
 
-       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
+       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
+               WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
        tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
 
        if (dc->soc->supports_border_color)
                tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
 
+       tegra_dc_stats_reset(&dc->stats);
+
        return 0;
 
 cleanup:
@@ -1826,8 +1893,20 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
        .has_powergate = true,
 };
 
+static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
+       .supports_border_color = false,
+       .supports_interlacing = true,
+       .supports_cursor = true,
+       .supports_block_linear = true,
+       .pitch_align = 64,
+       .has_powergate = true,
+};
+
 static const struct of_device_id tegra_dc_of_match[] = {
        {
+               .compatible = "nvidia,tegra210-dc",
+               .data = &tegra210_dc_soc_info,
+       }, {
                .compatible = "nvidia,tegra124-dc",
                .data = &tegra124_dc_soc_info,
        }, {
@@ -1957,6 +2036,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
+       dc->syncpt = host1x_syncpt_request(&pdev->dev, flags);
+       if (!dc->syncpt)
+               dev_warn(&pdev->dev, "failed to allocate syncpoint\n");
+
        INIT_LIST_HEAD(&dc->client.list);
        dc->client.ops = &dc_client_ops;
        dc->client.dev = &pdev->dev;
@@ -1974,10 +2057,6 @@ 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;
@@ -2016,7 +2095,6 @@ static int tegra_dc_remove(struct platform_device *pdev)
 struct platform_driver tegra_dc_driver = {
        .driver = {
                .name = "tegra-dc",
-               .owner = THIS_MODULE,
                .of_match_table = tegra_dc_of_match,
        },
        .probe = tegra_dc_probe,
index 55792daabbb587b80712c684742c902c1303ee65..4a268635749bdc667ef3ec86b3c7e3774f1faf09 100644 (file)
 #define DC_CMD_REG_ACT_CONTROL                 0x043
 
 #define DC_COM_CRC_CONTROL                     0x300
+#define  DC_COM_CRC_CONTROL_ALWAYS (1 << 3)
+#define  DC_COM_CRC_CONTROL_FULL_FRAME  (0 << 2)
+#define  DC_COM_CRC_CONTROL_ACTIVE_DATA (1 << 2)
+#define  DC_COM_CRC_CONTROL_WAIT (1 << 1)
+#define  DC_COM_CRC_CONTROL_ENABLE (1 << 0)
 #define DC_COM_CRC_CHECKSUM                    0x301
 #define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
 #define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
 #define DC_COM_CRC_CHECKSUM_LATCHED            0x329
 
 #define DC_DISP_DISP_SIGNAL_OPTIONS0           0x400
-#define H_PULSE_0_ENABLE (1 <<  8)
-#define H_PULSE_1_ENABLE (1 << 10)
-#define H_PULSE_2_ENABLE (1 << 12)
+#define H_PULSE0_ENABLE (1 <<  8)
+#define H_PULSE1_ENABLE (1 << 10)
+#define H_PULSE2_ENABLE (1 << 12)
 
 #define DC_DISP_DISP_SIGNAL_OPTIONS1           0x401
 
 #define DC_DISP_DISP_WIN_OPTIONS               0x402
 #define HDMI_ENABLE    (1 << 30)
 #define DSI_ENABLE     (1 << 29)
+#define SOR1_TIMING_CYA        (1 << 27)
+#define SOR1_ENABLE    (1 << 26)
 #define SOR_ENABLE     (1 << 25)
 #define CURSOR_ENABLE  (1 << 16)
 
 #define BASE_COLOR_SIZE565     (6 << 0)
 #define BASE_COLOR_SIZE332     (7 << 0)
 #define BASE_COLOR_SIZE888     (8 << 0)
+#define DITHER_CONTROL_MASK    (3 << 8)
 #define DITHER_CONTROL_DISABLE (0 << 8)
 #define DITHER_CONTROL_ORDERED (2 << 8)
 #define DITHER_CONTROL_ERRDIFF (3 << 8)
+#define BASE_COLOR_SIZE_MASK   (0xf << 0)
+#define BASE_COLOR_SIZE_666    (0 << 0)
+#define BASE_COLOR_SIZE_111    (1 << 0)
+#define BASE_COLOR_SIZE_222    (2 << 0)
+#define BASE_COLOR_SIZE_333    (3 << 0)
+#define BASE_COLOR_SIZE_444    (4 << 0)
+#define BASE_COLOR_SIZE_555    (5 << 0)
+#define BASE_COLOR_SIZE_565    (6 << 0)
+#define BASE_COLOR_SIZE_332    (7 << 0)
+#define BASE_COLOR_SIZE_888    (8 << 0)
 
 #define DC_DISP_SHIFT_CLOCK_OPTIONS            0x431
 #define  SC1_H_QUALIFIER_NONE  (1 << 16)
index 07b26972f487967cb1b4203488f0387c9e0736fc..224a7dc8e4ed683a40bd0456045ca6e02fbaaa18 100644 (file)
@@ -294,26 +294,41 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
        }
 
        dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux");
-       if (IS_ERR(dpaux->rst))
+       if (IS_ERR(dpaux->rst)) {
+               dev_err(&pdev->dev, "failed to get reset control: %ld\n",
+                       PTR_ERR(dpaux->rst));
                return PTR_ERR(dpaux->rst);
+       }
 
        dpaux->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(dpaux->clk))
+       if (IS_ERR(dpaux->clk)) {
+               dev_err(&pdev->dev, "failed to get module clock: %ld\n",
+                       PTR_ERR(dpaux->clk));
                return PTR_ERR(dpaux->clk);
+       }
 
        err = clk_prepare_enable(dpaux->clk);
-       if (err < 0)
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to enable module clock: %d\n",
+                       err);
                return err;
+       }
 
        reset_control_deassert(dpaux->rst);
 
        dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent");
-       if (IS_ERR(dpaux->clk_parent))
+       if (IS_ERR(dpaux->clk_parent)) {
+               dev_err(&pdev->dev, "failed to get parent clock: %ld\n",
+                       PTR_ERR(dpaux->clk_parent));
                return PTR_ERR(dpaux->clk_parent);
+       }
 
        err = clk_prepare_enable(dpaux->clk_parent);
-       if (err < 0)
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to enable parent clock: %d\n",
+                       err);
                return err;
+       }
 
        err = clk_set_rate(dpaux->clk_parent, 270000000);
        if (err < 0) {
@@ -323,8 +338,11 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
        }
 
        dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd");
-       if (IS_ERR(dpaux->vdd))
+       if (IS_ERR(dpaux->vdd)) {
+               dev_err(&pdev->dev, "failed to get VDD supply: %ld\n",
+                       PTR_ERR(dpaux->vdd));
                return PTR_ERR(dpaux->vdd);
+       }
 
        err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0,
                               dev_name(dpaux->dev), dpaux);
@@ -334,6 +352,8 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
                return err;
        }
 
+       disable_irq(dpaux->irq);
+
        dpaux->aux.transfer = tegra_dpaux_transfer;
        dpaux->aux.dev = &pdev->dev;
 
@@ -341,6 +361,24 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
+       /*
+        * Assume that by default the DPAUX/I2C pads will be used for HDMI,
+        * so power them up and configure them in I2C mode.
+        *
+        * The DPAUX code paths reconfigure the pads in AUX mode, but there
+        * is no possibility to perform the I2C mode configuration in the
+        * HDMI path.
+        */
+       value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
+       value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
+       tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
+
+       value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_PADCTL);
+       value = DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV |
+               DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV |
+               DPAUX_HYBRID_PADCTL_MODE_I2C;
+       tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL);
+
        /* enable and clear all interrupts */
        value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT |
                DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT;
@@ -359,6 +397,12 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
 static int tegra_dpaux_remove(struct platform_device *pdev)
 {
        struct tegra_dpaux *dpaux = platform_get_drvdata(pdev);
+       u32 value;
+
+       /* make sure pads are powered down when not in use */
+       value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
+       value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
+       tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
 
        drm_dp_aux_unregister(&dpaux->aux);
 
@@ -376,6 +420,7 @@ static int tegra_dpaux_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id tegra_dpaux_of_match[] = {
+       { .compatible = "nvidia,tegra210-dpaux", },
        { .compatible = "nvidia,tegra124-dpaux", },
        { },
 };
@@ -425,8 +470,10 @@ int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output)
                enum drm_connector_status status;
 
                status = tegra_dpaux_detect(dpaux);
-               if (status == connector_status_connected)
+               if (status == connector_status_connected) {
+                       enable_irq(dpaux->irq);
                        return 0;
+               }
 
                usleep_range(1000, 2000);
        }
@@ -439,6 +486,8 @@ int tegra_dpaux_detach(struct tegra_dpaux *dpaux)
        unsigned long timeout;
        int err;
 
+       disable_irq(dpaux->irq);
+
        err = regulator_disable(dpaux->vdd);
        if (err < 0)
                return err;
index 806e245ca7874d3929e7f22227096d630d37cc13..20783d9f4728fb5ff1de8ce361e165e8ede5c609 100644 (file)
@@ -57,6 +57,8 @@
 #define DPAUX_DP_AUX_CONFIG 0x45
 
 #define DPAUX_HYBRID_PADCTL 0x49
+#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV (1 << 15)
+#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV (1 << 14)
 #define DPAUX_HYBRID_PADCTL_AUX_CMH(x) (((x) & 0x3) << 12)
 #define DPAUX_HYBRID_PADCTL_AUX_DRVZ(x) (((x) & 0x7) << 8)
 #define DPAUX_HYBRID_PADCTL_AUX_DRVI(x) (((x) & 0x3f) << 2)
index 427f50c6803cba7d3ed5424547ac7c812d6bb536..6d88cf1fcd1cd3e0a6335fa766d8ca578c0815e3 100644 (file)
@@ -171,8 +171,6 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
        if (err < 0)
                goto fbdev;
 
-       drm_mode_config_reset(drm);
-
        /*
         * We don't use the drm_irq_install() helpers provided by the DRM
         * core, so we need to set this manually in order to allow the
@@ -182,11 +180,14 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
 
        /* syncpoints are used for full 32-bit hardware VBLANK counters */
        drm->max_vblank_count = 0xffffffff;
+       drm->vblank_disable_allowed = true;
 
        err = drm_vblank_init(drm, drm->mode_config.num_crtc);
        if (err < 0)
                goto device;
 
+       drm_mode_config_reset(drm);
+
        err = tegra_drm_fb_init(drm);
        if (err < 0)
                goto vblank;
@@ -1037,9 +1038,8 @@ static int host1x_drm_resume(struct device *dev)
 }
 #endif
 
-static const struct dev_pm_ops host1x_drm_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(host1x_drm_suspend, host1x_drm_resume)
-};
+static SIMPLE_DEV_PM_OPS(host1x_drm_pm_ops, host1x_drm_suspend,
+                        host1x_drm_resume);
 
 static const struct of_device_id host1x_drm_subdevs[] = {
        { .compatible = "nvidia,tegra20-dc", },
@@ -1056,6 +1056,12 @@ static const struct of_device_id host1x_drm_subdevs[] = {
        { .compatible = "nvidia,tegra124-dc", },
        { .compatible = "nvidia,tegra124-sor", },
        { .compatible = "nvidia,tegra124-hdmi", },
+       { .compatible = "nvidia,tegra124-dsi", },
+       { .compatible = "nvidia,tegra132-dsi", },
+       { .compatible = "nvidia,tegra210-dc", },
+       { .compatible = "nvidia,tegra210-dsi", },
+       { .compatible = "nvidia,tegra210-sor", },
+       { .compatible = "nvidia,tegra210-sor1", },
        { /* sentinel */ }
 };
 
index 659b2fcc986dcf1c8ef4abc7364f288b128a3411..ec49275ffb247c419a70a2f8aed9cd7d922c46d6 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <uapi/drm/tegra_drm.h>
 #include <linux/host1x.h>
+#include <linux/of_gpio.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
@@ -104,6 +105,13 @@ int tegra_drm_exit(struct tegra_drm *tegra);
 struct tegra_dc_soc_info;
 struct tegra_output;
 
+struct tegra_dc_stats {
+       unsigned long frames;
+       unsigned long vblank;
+       unsigned long underflow;
+       unsigned long overflow;
+};
+
 struct tegra_dc {
        struct host1x_client client;
        struct host1x_syncpt *syncpt;
@@ -121,6 +129,7 @@ struct tegra_dc {
 
        struct tegra_output *rgb;
 
+       struct tegra_dc_stats stats;
        struct list_head list;
 
        struct drm_info_list *debugfs_files;
@@ -200,6 +209,7 @@ struct tegra_output {
        const struct edid *edid;
        unsigned int hpd_irq;
        int hpd_gpio;
+       enum of_gpio_flags hpd_gpio_flags;
 
        struct drm_encoder encoder;
        struct drm_connector connector;
index ed970f62290306e5c78158f9600211d51251dc78..f0a138ef68ce8935bdb33d0a9c6191989b77c7f9 100644 (file)
@@ -119,6 +119,16 @@ static int tegra_dsi_show_regs(struct seq_file *s, void *data)
 {
        struct drm_info_node *node = s->private;
        struct tegra_dsi *dsi = node->info_ent->data;
+       struct drm_crtc *crtc = dsi->output.encoder.crtc;
+       struct drm_device *drm = node->minor->dev;
+       int err = 0;
+
+       drm_modeset_lock_all(drm);
+
+       if (!crtc || !crtc->state->active) {
+               err = -EBUSY;
+               goto unlock;
+       }
 
 #define DUMP_REG(name)                                         \
        seq_printf(s, "%-32s %#05x %08x\n", #name, name,        \
@@ -208,7 +218,9 @@ static int tegra_dsi_show_regs(struct seq_file *s, void *data)
 
 #undef DUMP_REG
 
-       return 0;
+unlock:
+       drm_modeset_unlock_all(drm);
+       return err;
 }
 
 static struct drm_info_list debugfs_files[] = {
@@ -548,14 +560,19 @@ static void tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
 
                /* horizontal sync width */
                hsw = (mode->hsync_end - mode->hsync_start) * mul / div;
-               hsw -= 10;
 
                /* horizontal back porch */
                hbp = (mode->htotal - mode->hsync_end) * mul / div;
-               hbp -= 14;
+
+               if ((dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0)
+                       hbp += hsw;
 
                /* horizontal front porch */
                hfp = (mode->hsync_start - mode->hdisplay) * mul / div;
+
+               /* subtract packet overhead */
+               hsw -= 10;
+               hbp -= 14;
                hfp -= 8;
 
                tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
@@ -726,10 +743,6 @@ static void tegra_dsi_soft_reset(struct tegra_dsi *dsi)
                tegra_dsi_soft_reset(dsi->slave);
 }
 
-static void tegra_dsi_connector_dpms(struct drm_connector *connector, int mode)
-{
-}
-
 static void tegra_dsi_connector_reset(struct drm_connector *connector)
 {
        struct tegra_dsi_state *state;
@@ -756,7 +769,7 @@ tegra_dsi_connector_duplicate_state(struct drm_connector *connector)
 }
 
 static const struct drm_connector_funcs tegra_dsi_connector_funcs = {
-       .dpms = tegra_dsi_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .reset = tegra_dsi_connector_reset,
        .detect = tegra_output_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@ -782,22 +795,48 @@ static const struct drm_encoder_funcs tegra_dsi_encoder_funcs = {
        .destroy = tegra_output_encoder_destroy,
 };
 
-static void tegra_dsi_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
 {
-}
+       struct tegra_output *output = encoder_to_output(encoder);
+       struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+       struct tegra_dsi *dsi = to_dsi(output);
+       u32 value;
+       int err;
 
-static void tegra_dsi_encoder_prepare(struct drm_encoder *encoder)
-{
-}
+       if (output->panel)
+               drm_panel_disable(output->panel);
 
-static void tegra_dsi_encoder_commit(struct drm_encoder *encoder)
-{
+       tegra_dsi_video_disable(dsi);
+
+       /*
+        * The following accesses registers of the display controller, so make
+        * sure it's only executed when the output is attached to one.
+        */
+       if (dc) {
+               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+               value &= ~DSI_ENABLE;
+               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+               tegra_dc_commit(dc);
+       }
+
+       err = tegra_dsi_wait_idle(dsi, 100);
+       if (err < 0)
+               dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
+
+       tegra_dsi_soft_reset(dsi);
+
+       if (output->panel)
+               drm_panel_unprepare(output->panel);
+
+       tegra_dsi_disable(dsi);
+
+       return;
 }
 
-static void tegra_dsi_encoder_mode_set(struct drm_encoder *encoder,
-                                      struct drm_display_mode *mode,
-                                      struct drm_display_mode *adjusted)
+static void tegra_dsi_encoder_enable(struct drm_encoder *encoder)
 {
+       struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
        struct tegra_output *output = encoder_to_output(encoder);
        struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
        struct tegra_dsi *dsi = to_dsi(output);
@@ -835,45 +874,6 @@ static void tegra_dsi_encoder_mode_set(struct drm_encoder *encoder,
        return;
 }
 
-static void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
-{
-       struct tegra_output *output = encoder_to_output(encoder);
-       struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
-       struct tegra_dsi *dsi = to_dsi(output);
-       u32 value;
-       int err;
-
-       if (output->panel)
-               drm_panel_disable(output->panel);
-
-       tegra_dsi_video_disable(dsi);
-
-       /*
-        * The following accesses registers of the display controller, so make
-        * sure it's only executed when the output is attached to one.
-        */
-       if (dc) {
-               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
-               value &= ~DSI_ENABLE;
-               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
-
-               tegra_dc_commit(dc);
-       }
-
-       err = tegra_dsi_wait_idle(dsi, 100);
-       if (err < 0)
-               dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
-
-       tegra_dsi_soft_reset(dsi);
-
-       if (output->panel)
-               drm_panel_unprepare(output->panel);
-
-       tegra_dsi_disable(dsi);
-
-       return;
-}
-
 static int
 tegra_dsi_encoder_atomic_check(struct drm_encoder *encoder,
                               struct drm_crtc_state *crtc_state,
@@ -956,11 +956,8 @@ tegra_dsi_encoder_atomic_check(struct drm_encoder *encoder,
 }
 
 static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = {
-       .dpms = tegra_dsi_encoder_dpms,
-       .prepare = tegra_dsi_encoder_prepare,
-       .commit = tegra_dsi_encoder_commit,
-       .mode_set = tegra_dsi_encoder_mode_set,
        .disable = tegra_dsi_encoder_disable,
+       .enable = tegra_dsi_encoder_enable,
        .atomic_check = tegra_dsi_encoder_atomic_check,
 };
 
@@ -992,6 +989,10 @@ static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
                DSI_PAD_OUT_CLK(0x0);
        tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
 
+       value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
+               DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
+       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
+
        return tegra_mipi_calibrate(dsi->mipi);
 }
 
@@ -1621,6 +1622,9 @@ static int tegra_dsi_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id tegra_dsi_of_match[] = {
+       { .compatible = "nvidia,tegra210-dsi", },
+       { .compatible = "nvidia,tegra132-dsi", },
+       { .compatible = "nvidia,tegra124-dsi", },
        { .compatible = "nvidia,tegra114-dsi", },
        { },
 };
index bad1006a51509da2868d83115245cb742ec29385..2192636153991fbcd554d1a1125862e81cfcbbe7 100644 (file)
 #define DSI_PAD_SLEW_DN(x)             (((x) & 0x7) << 12)
 #define DSI_PAD_SLEW_UP(x)             (((x) & 0x7) << 16)
 #define DSI_PAD_CONTROL_3              0x51
+#define  DSI_PAD_PREEMP_PD_CLK(x)      (((x) & 0x3) << 12)
+#define  DSI_PAD_PREEMP_PU_CLK(x)      (((x) & 0x3) << 8)
+#define  DSI_PAD_PREEMP_PD(x)          (((x) & 0x3) << 4)
+#define  DSI_PAD_PREEMP_PU(x)          (((x) & 0x3) << 0)
 #define DSI_PAD_CONTROL_4              0x52
 #define DSI_GANGED_MODE_CONTROL                0x53
 #define DSI_GANGED_MODE_CONTROL_ENABLE (1 << 0)
index 397fb34d5d5bdd842012f0842450b05e9d7139d1..07c844b746b446f89bc5de7933bdc607baee7940 100644 (file)
@@ -184,9 +184,9 @@ unreference:
 #ifdef CONFIG_DRM_TEGRA_FBDEV
 static struct fb_ops tegra_fb_ops = {
        .owner = THIS_MODULE,
-       .fb_fillrect = sys_fillrect,
-       .fb_copyarea = sys_copyarea,
-       .fb_imageblit = sys_imageblit,
+       .fb_fillrect = drm_fb_helper_sys_fillrect,
+       .fb_copyarea = drm_fb_helper_sys_copyarea,
+       .fb_imageblit = drm_fb_helper_sys_imageblit,
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = drm_fb_helper_set_par,
        .fb_blank = drm_fb_helper_blank,
@@ -224,11 +224,11 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
        if (IS_ERR(bo))
                return PTR_ERR(bo);
 
-       info = framebuffer_alloc(0, drm->dev);
-       if (!info) {
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info)) {
                dev_err(drm->dev, "failed to allocate framebuffer info\n");
                drm_gem_object_unreference_unlocked(&bo->gem);
-               return -ENOMEM;
+               return PTR_ERR(info);
        }
 
        fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1);
@@ -248,12 +248,6 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
        info->flags = FBINFO_FLAG_DEFAULT;
        info->fbops = &tegra_fb_ops;
 
-       err = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (err < 0) {
-               dev_err(drm->dev, "failed to allocate color map: %d\n", err);
-               goto destroy;
-       }
-
        drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
        drm_fb_helper_fill_var(info, helper, fb->width, fb->height);
 
@@ -282,7 +276,7 @@ destroy:
        drm_framebuffer_unregister_private(fb);
        tegra_fb_destroy(fb);
 release:
-       framebuffer_release(info);
+       drm_fb_helper_release_fbi(helper);
        return err;
 }
 
@@ -347,20 +341,9 @@ fini:
 
 static void tegra_fbdev_exit(struct tegra_fbdev *fbdev)
 {
-       struct fb_info *info = fbdev->base.fbdev;
-
-       if (info) {
-               int err;
 
-               err = unregister_framebuffer(info);
-               if (err < 0)
-                       DRM_DEBUG_KMS("failed to unregister framebuffer\n");
-
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&fbdev->base);
+       drm_fb_helper_release_fbi(&fbdev->base);
 
        if (fbdev->fb) {
                drm_framebuffer_unregister_private(&fbdev->fb->base);
index 06ab1783bba11e7b1299e3d950accf1547e20285..52b32cbd9de665c6e017218e1cd1b0e3782a994b 100644 (file)
@@ -772,13 +772,8 @@ static bool tegra_output_is_hdmi(struct tegra_output *output)
        return drm_detect_hdmi_monitor(edid);
 }
 
-static void tegra_hdmi_connector_dpms(struct drm_connector *connector,
-                                     int mode)
-{
-}
-
 static const struct drm_connector_funcs tegra_hdmi_connector_funcs = {
-       .dpms = tegra_hdmi_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .reset = drm_atomic_helper_connector_reset,
        .detect = tegra_output_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@ -818,22 +813,27 @@ static const struct drm_encoder_funcs tegra_hdmi_encoder_funcs = {
        .destroy = tegra_output_encoder_destroy,
 };
 
-static void tegra_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder)
 {
-}
+       struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+       u32 value;
 
-static void tegra_hdmi_encoder_prepare(struct drm_encoder *encoder)
-{
-}
+       /*
+        * The following accesses registers of the display controller, so make
+        * sure it's only executed when the output is attached to one.
+        */
+       if (dc) {
+               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+               value &= ~HDMI_ENABLE;
+               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
 
-static void tegra_hdmi_encoder_commit(struct drm_encoder *encoder)
-{
+               tegra_dc_commit(dc);
+       }
 }
 
-static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder,
-                                       struct drm_display_mode *mode,
-                                       struct drm_display_mode *adjusted)
+static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder)
 {
+       struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
        unsigned int h_sync_width, h_front_porch, h_back_porch, i, rekey;
        struct tegra_output *output = encoder_to_output(encoder);
        struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
@@ -872,13 +872,13 @@ static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder,
 
        tegra_dc_writel(dc, VSYNC_H_POSITION(1),
                        DC_DISP_DISP_TIMING_OPTIONS);
-       tegra_dc_writel(dc, DITHER_CONTROL_DISABLE | BASE_COLOR_SIZE888,
+       tegra_dc_writel(dc, DITHER_CONTROL_DISABLE | BASE_COLOR_SIZE_888,
                        DC_DISP_DISP_COLOR_CONTROL);
 
        /* video_preamble uses h_pulse2 */
        pulse_start = 1 + h_sync_width + h_back_porch - 10;
 
-       tegra_dc_writel(dc, H_PULSE_2_ENABLE, DC_DISP_DISP_SIGNAL_OPTIONS0);
+       tegra_dc_writel(dc, H_PULSE2_ENABLE, DC_DISP_DISP_SIGNAL_OPTIONS0);
 
        value = PULSE_MODE_NORMAL | PULSE_POLARITY_HIGH | PULSE_QUAL_VACTIVE |
                PULSE_LAST_END_A;
@@ -1035,24 +1035,6 @@ static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder,
        /* TODO: add HDCP support */
 }
 
-static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder)
-{
-       struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
-       u32 value;
-
-       /*
-        * The following accesses registers of the display controller, so make
-        * sure it's only executed when the output is attached to one.
-        */
-       if (dc) {
-               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
-               value &= ~HDMI_ENABLE;
-               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
-
-               tegra_dc_commit(dc);
-       }
-}
-
 static int
 tegra_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
                                struct drm_crtc_state *crtc_state,
@@ -1075,11 +1057,8 @@ tegra_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
 }
 
 static const struct drm_encoder_helper_funcs tegra_hdmi_encoder_helper_funcs = {
-       .dpms = tegra_hdmi_encoder_dpms,
-       .prepare = tegra_hdmi_encoder_prepare,
-       .commit = tegra_hdmi_encoder_commit,
-       .mode_set = tegra_hdmi_encoder_mode_set,
        .disable = tegra_hdmi_encoder_disable,
+       .enable = tegra_hdmi_encoder_enable,
        .atomic_check = tegra_hdmi_encoder_atomic_check,
 };
 
@@ -1087,11 +1066,16 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data)
 {
        struct drm_info_node *node = s->private;
        struct tegra_hdmi *hdmi = node->info_ent->data;
-       int err;
+       struct drm_crtc *crtc = hdmi->output.encoder.crtc;
+       struct drm_device *drm = node->minor->dev;
+       int err = 0;
 
-       err = clk_prepare_enable(hdmi->clk);
-       if (err)
-               return err;
+       drm_modeset_lock_all(drm);
+
+       if (!crtc || !crtc->state->active) {
+               err = -EBUSY;
+               goto unlock;
+       }
 
 #define DUMP_REG(name)                                         \
        seq_printf(s, "%-56s %#05x %08x\n", #name, name,        \
@@ -1258,9 +1242,9 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data)
 
 #undef DUMP_REG
 
-       clk_disable_unprepare(hdmi->clk);
-
-       return 0;
+unlock:
+       drm_modeset_unlock_all(drm);
+       return err;
 }
 
 static struct drm_info_list debugfs_files[] = {
index 37db47975d486bfd4ce982e93cdfee59fcfc2a8c..46664b6222707e3d4e51e4629305268711503c33 100644 (file)
@@ -7,8 +7,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/of_gpio.h>
-
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_panel.h>
 #include "drm.h"
@@ -59,10 +57,17 @@ tegra_output_connector_detect(struct drm_connector *connector, bool force)
        enum drm_connector_status status = connector_status_unknown;
 
        if (gpio_is_valid(output->hpd_gpio)) {
-               if (gpio_get_value(output->hpd_gpio) == 0)
-                       status = connector_status_disconnected;
-               else
-                       status = connector_status_connected;
+               if (output->hpd_gpio_flags & OF_GPIO_ACTIVE_LOW) {
+                       if (gpio_get_value(output->hpd_gpio) != 0)
+                               status = connector_status_disconnected;
+                       else
+                               status = connector_status_connected;
+               } else {
+                       if (gpio_get_value(output->hpd_gpio) == 0)
+                               status = connector_status_disconnected;
+                       else
+                               status = connector_status_connected;
+               }
        } else {
                if (!output->panel)
                        status = connector_status_disconnected;
@@ -97,7 +102,6 @@ static irqreturn_t hpd_irq(int irq, void *data)
 int tegra_output_probe(struct tegra_output *output)
 {
        struct device_node *ddc, *panel;
-       enum of_gpio_flags flags;
        int err, size;
 
        if (!output->of_node)
@@ -128,7 +132,7 @@ int tegra_output_probe(struct tegra_output *output)
 
        output->hpd_gpio = of_get_named_gpio_flags(output->of_node,
                                                   "nvidia,hpd-gpio", 0,
-                                                  &flags);
+                                                  &output->hpd_gpio_flags);
        if (gpio_is_valid(output->hpd_gpio)) {
                unsigned long flags;
 
index 7cd833f5b5b591257da40c04efc209057ec62549..bc9735b4ad605a21d304ccaf39d5d0038e7e8512 100644 (file)
@@ -18,7 +18,6 @@
 struct tegra_rgb {
        struct tegra_output output;
        struct tegra_dc *dc;
-       bool enabled;
 
        struct clk *clk_parent;
        struct clk *clk;
@@ -88,13 +87,8 @@ static void tegra_dc_write_regs(struct tegra_dc *dc,
                tegra_dc_writel(dc, table[i].value, table[i].offset);
 }
 
-static void tegra_rgb_connector_dpms(struct drm_connector *connector,
-                                    int mode)
-{
-}
-
 static const struct drm_connector_funcs tegra_rgb_connector_funcs = {
-       .dpms = tegra_rgb_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .reset = drm_atomic_helper_connector_reset,
        .detect = tegra_output_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@ -125,21 +119,22 @@ static const struct drm_encoder_funcs tegra_rgb_encoder_funcs = {
        .destroy = tegra_output_encoder_destroy,
 };
 
-static void tegra_rgb_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void tegra_rgb_encoder_disable(struct drm_encoder *encoder)
 {
-}
+       struct tegra_output *output = encoder_to_output(encoder);
+       struct tegra_rgb *rgb = to_rgb(output);
 
-static void tegra_rgb_encoder_prepare(struct drm_encoder *encoder)
-{
-}
+       if (output->panel)
+               drm_panel_disable(output->panel);
 
-static void tegra_rgb_encoder_commit(struct drm_encoder *encoder)
-{
+       tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
+       tegra_dc_commit(rgb->dc);
+
+       if (output->panel)
+               drm_panel_unprepare(output->panel);
 }
 
-static void tegra_rgb_encoder_mode_set(struct drm_encoder *encoder,
-                                      struct drm_display_mode *mode,
-                                      struct drm_display_mode *adjusted)
+static void tegra_rgb_encoder_enable(struct drm_encoder *encoder)
 {
        struct tegra_output *output = encoder_to_output(encoder);
        struct tegra_rgb *rgb = to_rgb(output);
@@ -174,21 +169,6 @@ static void tegra_rgb_encoder_mode_set(struct drm_encoder *encoder,
                drm_panel_enable(output->panel);
 }
 
-static void tegra_rgb_encoder_disable(struct drm_encoder *encoder)
-{
-       struct tegra_output *output = encoder_to_output(encoder);
-       struct tegra_rgb *rgb = to_rgb(output);
-
-       if (output->panel)
-               drm_panel_disable(output->panel);
-
-       tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
-       tegra_dc_commit(rgb->dc);
-
-       if (output->panel)
-               drm_panel_unprepare(output->panel);
-}
-
 static int
 tegra_rgb_encoder_atomic_check(struct drm_encoder *encoder,
                               struct drm_crtc_state *crtc_state,
@@ -231,11 +211,8 @@ tegra_rgb_encoder_atomic_check(struct drm_encoder *encoder,
 }
 
 static const struct drm_encoder_helper_funcs tegra_rgb_encoder_helper_funcs = {
-       .dpms = tegra_rgb_encoder_dpms,
-       .prepare = tegra_rgb_encoder_prepare,
-       .commit = tegra_rgb_encoder_commit,
-       .mode_set = tegra_rgb_encoder_mode_set,
        .disable = tegra_rgb_encoder_disable,
+       .enable = tegra_rgb_encoder_enable,
        .atomic_check = tegra_rgb_encoder_atomic_check,
 };
 
index 7591d8901f9a24ddd61d035500116c617e4df3f6..da1715ebdd7118c698621e574764b0054aeb125b 100644 (file)
@@ -10,7 +10,9 @@
 #include <linux/debugfs.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 
 #include <soc/tegra/pmc.h>
 #include "drm.h"
 #include "sor.h"
 
+#define SOR_REKEY 0x38
+
+struct tegra_sor_hdmi_settings {
+       unsigned long frequency;
+
+       u8 vcocap;
+       u8 ichpmp;
+       u8 loadadj;
+       u8 termadj;
+       u8 tx_pu;
+       u8 bg_vref;
+
+       u8 drive_current[4];
+       u8 preemphasis[4];
+};
+
+#if 1
+static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_defaults[] = {
+       {
+               .frequency = 54000000,
+               .vcocap = 0x0,
+               .ichpmp = 0x1,
+               .loadadj = 0x3,
+               .termadj = 0x9,
+               .tx_pu = 0x10,
+               .bg_vref = 0x8,
+               .drive_current = { 0x33, 0x3a, 0x3a, 0x3a },
+               .preemphasis = { 0x00, 0x00, 0x00, 0x00 },
+       }, {
+               .frequency = 75000000,
+               .vcocap = 0x3,
+               .ichpmp = 0x1,
+               .loadadj = 0x3,
+               .termadj = 0x9,
+               .tx_pu = 0x40,
+               .bg_vref = 0x8,
+               .drive_current = { 0x33, 0x3a, 0x3a, 0x3a },
+               .preemphasis = { 0x00, 0x00, 0x00, 0x00 },
+       }, {
+               .frequency = 150000000,
+               .vcocap = 0x3,
+               .ichpmp = 0x1,
+               .loadadj = 0x3,
+               .termadj = 0x9,
+               .tx_pu = 0x66,
+               .bg_vref = 0x8,
+               .drive_current = { 0x33, 0x3a, 0x3a, 0x3a },
+               .preemphasis = { 0x00, 0x00, 0x00, 0x00 },
+       }, {
+               .frequency = 300000000,
+               .vcocap = 0x3,
+               .ichpmp = 0x1,
+               .loadadj = 0x3,
+               .termadj = 0x9,
+               .tx_pu = 0x66,
+               .bg_vref = 0xa,
+               .drive_current = { 0x33, 0x3f, 0x3f, 0x3f },
+               .preemphasis = { 0x00, 0x17, 0x17, 0x17 },
+       }, {
+               .frequency = 600000000,
+               .vcocap = 0x3,
+               .ichpmp = 0x1,
+               .loadadj = 0x3,
+               .termadj = 0x9,
+               .tx_pu = 0x66,
+               .bg_vref = 0x8,
+               .drive_current = { 0x33, 0x3f, 0x3f, 0x3f },
+               .preemphasis = { 0x00, 0x00, 0x00, 0x00 },
+       },
+};
+#else
+static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_defaults[] = {
+       {
+               .frequency = 75000000,
+               .vcocap = 0x3,
+               .ichpmp = 0x1,
+               .loadadj = 0x3,
+               .termadj = 0x9,
+               .tx_pu = 0x40,
+               .bg_vref = 0x8,
+               .drive_current = { 0x29, 0x29, 0x29, 0x29 },
+               .preemphasis = { 0x00, 0x00, 0x00, 0x00 },
+       }, {
+               .frequency = 150000000,
+               .vcocap = 0x3,
+               .ichpmp = 0x1,
+               .loadadj = 0x3,
+               .termadj = 0x9,
+               .tx_pu = 0x66,
+               .bg_vref = 0x8,
+               .drive_current = { 0x30, 0x37, 0x37, 0x37 },
+               .preemphasis = { 0x01, 0x02, 0x02, 0x02 },
+       }, {
+               .frequency = 300000000,
+               .vcocap = 0x3,
+               .ichpmp = 0x6,
+               .loadadj = 0x3,
+               .termadj = 0x9,
+               .tx_pu = 0x66,
+               .bg_vref = 0xf,
+               .drive_current = { 0x30, 0x37, 0x37, 0x37 },
+               .preemphasis = { 0x10, 0x3e, 0x3e, 0x3e },
+       }, {
+               .frequency = 600000000,
+               .vcocap = 0x3,
+               .ichpmp = 0xa,
+               .loadadj = 0x3,
+               .termadj = 0xb,
+               .tx_pu = 0x66,
+               .bg_vref = 0xe,
+               .drive_current = { 0x35, 0x3e, 0x3e, 0x3e },
+               .preemphasis = { 0x02, 0x3f, 0x3f, 0x3f },
+       },
+};
+#endif
+
+struct tegra_sor_soc {
+       bool supports_edp;
+       bool supports_lvds;
+       bool supports_hdmi;
+       bool supports_dp;
+
+       const struct tegra_sor_hdmi_settings *settings;
+       unsigned int num_settings;
+};
+
+struct tegra_sor;
+
+struct tegra_sor_ops {
+       const char *name;
+       int (*probe)(struct tegra_sor *sor);
+       int (*remove)(struct tegra_sor *sor);
+};
+
 struct tegra_sor {
        struct host1x_client client;
        struct tegra_output output;
        struct device *dev;
 
+       const struct tegra_sor_soc *soc;
        void __iomem *regs;
 
        struct reset_control *rst;
@@ -38,12 +175,19 @@ struct tegra_sor {
 
        struct tegra_dpaux *dpaux;
 
-       struct mutex lock;
-       bool enabled;
-
        struct drm_info_list *debugfs_files;
        struct drm_minor *minor;
        struct dentry *debugfs;
+
+       const struct tegra_sor_ops *ops;
+
+       /* for HDMI 2.0 */
+       struct tegra_sor_hdmi_settings *settings;
+       unsigned int num_settings;
+
+       struct regulator *avdd_io_supply;
+       struct regulator *vdd_pll_supply;
+       struct regulator *hdmi_supply;
 };
 
 struct tegra_sor_config {
@@ -94,40 +238,40 @@ static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
                SOR_LANE_DRIVE_CURRENT_LANE2(0x40) |
                SOR_LANE_DRIVE_CURRENT_LANE1(0x40) |
                SOR_LANE_DRIVE_CURRENT_LANE0(0x40);
-       tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT_0);
+       tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT0);
 
        value = SOR_LANE_PREEMPHASIS_LANE3(0x0f) |
                SOR_LANE_PREEMPHASIS_LANE2(0x0f) |
                SOR_LANE_PREEMPHASIS_LANE1(0x0f) |
                SOR_LANE_PREEMPHASIS_LANE0(0x0f);
-       tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS_0);
+       tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS0);
 
-       value = SOR_LANE_POST_CURSOR_LANE3(0x00) |
-               SOR_LANE_POST_CURSOR_LANE2(0x00) |
-               SOR_LANE_POST_CURSOR_LANE1(0x00) |
-               SOR_LANE_POST_CURSOR_LANE0(0x00);
-       tegra_sor_writel(sor, value, SOR_LANE_POST_CURSOR_0);
+       value = SOR_LANE_POSTCURSOR_LANE3(0x00) |
+               SOR_LANE_POSTCURSOR_LANE2(0x00) |
+               SOR_LANE_POSTCURSOR_LANE1(0x00) |
+               SOR_LANE_POSTCURSOR_LANE0(0x00);
+       tegra_sor_writel(sor, value, SOR_LANE_POSTCURSOR0);
 
        /* disable LVDS mode */
        tegra_sor_writel(sor, 0, SOR_LVDS);
 
-       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
        value |= SOR_DP_PADCTL_TX_PU_ENABLE;
        value &= ~SOR_DP_PADCTL_TX_PU_MASK;
        value |= SOR_DP_PADCTL_TX_PU(2); /* XXX: don't hardcode? */
-       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
 
-       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
        value |= SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 |
                 SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0;
-       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
 
        usleep_range(10, 100);
 
-       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
        value &= ~(SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 |
                   SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0);
-       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
 
        err = tegra_dpaux_prepare(sor->dpaux, DP_SET_ANSI_8B10B);
        if (err < 0)
@@ -148,11 +292,11 @@ static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
        if (err < 0)
                return err;
 
-       value = tegra_sor_readl(sor, SOR_DP_SPARE_0);
+       value = tegra_sor_readl(sor, SOR_DP_SPARE0);
        value |= SOR_DP_SPARE_SEQ_ENABLE;
        value &= ~SOR_DP_SPARE_PANEL_INTERNAL;
        value |= SOR_DP_SPARE_MACRO_SOR_CLK;
-       tegra_sor_writel(sor, value, SOR_DP_SPARE_0);
+       tegra_sor_writel(sor, value, SOR_DP_SPARE0);
 
        for (i = 0, value = 0; i < link->num_lanes; i++) {
                unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
@@ -187,18 +331,59 @@ static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
        return 0;
 }
 
+static void tegra_sor_dp_term_calibrate(struct tegra_sor *sor)
+{
+       u32 mask = 0x08, adj = 0, value;
+
+       /* enable pad calibration logic */
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
+       value &= ~SOR_DP_PADCTL_PAD_CAL_PD;
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
+
+       value = tegra_sor_readl(sor, SOR_PLL1);
+       value |= SOR_PLL1_TMDS_TERM;
+       tegra_sor_writel(sor, value, SOR_PLL1);
+
+       while (mask) {
+               adj |= mask;
+
+               value = tegra_sor_readl(sor, SOR_PLL1);
+               value &= ~SOR_PLL1_TMDS_TERMADJ_MASK;
+               value |= SOR_PLL1_TMDS_TERMADJ(adj);
+               tegra_sor_writel(sor, value, SOR_PLL1);
+
+               usleep_range(100, 200);
+
+               value = tegra_sor_readl(sor, SOR_PLL1);
+               if (value & SOR_PLL1_TERM_COMPOUT)
+                       adj &= ~mask;
+
+               mask >>= 1;
+       }
+
+       value = tegra_sor_readl(sor, SOR_PLL1);
+       value &= ~SOR_PLL1_TMDS_TERMADJ_MASK;
+       value |= SOR_PLL1_TMDS_TERMADJ(adj);
+       tegra_sor_writel(sor, value, SOR_PLL1);
+
+       /* disable pad calibration logic */
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
+       value |= SOR_DP_PADCTL_PAD_CAL_PD;
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
+}
+
 static void tegra_sor_super_update(struct tegra_sor *sor)
 {
-       tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0);
-       tegra_sor_writel(sor, 1, SOR_SUPER_STATE_0);
-       tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0);
+       tegra_sor_writel(sor, 0, SOR_SUPER_STATE0);
+       tegra_sor_writel(sor, 1, SOR_SUPER_STATE0);
+       tegra_sor_writel(sor, 0, SOR_SUPER_STATE0);
 }
 
 static void tegra_sor_update(struct tegra_sor *sor)
 {
-       tegra_sor_writel(sor, 0, SOR_STATE_0);
-       tegra_sor_writel(sor, 1, SOR_STATE_0);
-       tegra_sor_writel(sor, 0, SOR_STATE_0);
+       tegra_sor_writel(sor, 0, SOR_STATE0);
+       tegra_sor_writel(sor, 1, SOR_STATE0);
+       tegra_sor_writel(sor, 0, SOR_STATE0);
 }
 
 static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout)
@@ -235,16 +420,16 @@ static int tegra_sor_attach(struct tegra_sor *sor)
        unsigned long value, timeout;
 
        /* wake up in normal mode */
-       value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+       value = tegra_sor_readl(sor, SOR_SUPER_STATE1);
        value |= SOR_SUPER_STATE_HEAD_MODE_AWAKE;
        value |= SOR_SUPER_STATE_MODE_NORMAL;
-       tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+       tegra_sor_writel(sor, value, SOR_SUPER_STATE1);
        tegra_sor_super_update(sor);
 
        /* attach */
-       value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+       value = tegra_sor_readl(sor, SOR_SUPER_STATE1);
        value |= SOR_SUPER_STATE_ATTACHED;
-       tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+       tegra_sor_writel(sor, value, SOR_SUPER_STATE1);
        tegra_sor_super_update(sor);
 
        timeout = jiffies + msecs_to_jiffies(250);
@@ -385,7 +570,7 @@ static int tegra_sor_compute_params(struct tegra_sor *sor,
 }
 
 static int tegra_sor_calc_config(struct tegra_sor *sor,
-                                struct drm_display_mode *mode,
+                                const struct drm_display_mode *mode,
                                 struct tegra_sor_config *config,
                                 struct drm_dp_link *link)
 {
@@ -481,9 +666,9 @@ static int tegra_sor_detach(struct tegra_sor *sor)
        unsigned long value, timeout;
 
        /* switch to safe mode */
-       value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+       value = tegra_sor_readl(sor, SOR_SUPER_STATE1);
        value &= ~SOR_SUPER_STATE_MODE_NORMAL;
-       tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+       tegra_sor_writel(sor, value, SOR_SUPER_STATE1);
        tegra_sor_super_update(sor);
 
        timeout = jiffies + msecs_to_jiffies(250);
@@ -498,15 +683,15 @@ static int tegra_sor_detach(struct tegra_sor *sor)
                return -ETIMEDOUT;
 
        /* go to sleep */
-       value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+       value = tegra_sor_readl(sor, SOR_SUPER_STATE1);
        value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK;
-       tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+       tegra_sor_writel(sor, value, SOR_SUPER_STATE1);
        tegra_sor_super_update(sor);
 
        /* detach */
-       value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+       value = tegra_sor_readl(sor, SOR_SUPER_STATE1);
        value &= ~SOR_SUPER_STATE_ATTACHED;
-       tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+       tegra_sor_writel(sor, value, SOR_SUPER_STATE1);
        tegra_sor_super_update(sor);
 
        timeout = jiffies + msecs_to_jiffies(250);
@@ -552,10 +737,10 @@ static int tegra_sor_power_down(struct tegra_sor *sor)
        if (err < 0)
                dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
 
-       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
        value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
                   SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2);
-       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
 
        /* stop lane sequencer */
        value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_UP |
@@ -575,39 +760,26 @@ static int tegra_sor_power_down(struct tegra_sor *sor)
        if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0)
                return -ETIMEDOUT;
 
-       value = tegra_sor_readl(sor, SOR_PLL_2);
-       value |= SOR_PLL_2_PORT_POWERDOWN;
-       tegra_sor_writel(sor, value, SOR_PLL_2);
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value |= SOR_PLL2_PORT_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL2);
 
        usleep_range(20, 100);
 
-       value = tegra_sor_readl(sor, SOR_PLL_0);
-       value |= SOR_PLL_0_POWER_OFF;
-       value |= SOR_PLL_0_VCOPD;
-       tegra_sor_writel(sor, value, SOR_PLL_0);
+       value = tegra_sor_readl(sor, SOR_PLL0);
+       value |= SOR_PLL0_VCOPD | SOR_PLL0_PWR;
+       tegra_sor_writel(sor, value, SOR_PLL0);
 
-       value = tegra_sor_readl(sor, SOR_PLL_2);
-       value |= SOR_PLL_2_SEQ_PLLCAPPD;
-       value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
-       tegra_sor_writel(sor, value, SOR_PLL_2);
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value |= SOR_PLL2_SEQ_PLLCAPPD;
+       value |= SOR_PLL2_SEQ_PLLCAPPD_ENFORCE;
+       tegra_sor_writel(sor, value, SOR_PLL2);
 
        usleep_range(20, 100);
 
        return 0;
 }
 
-static int tegra_sor_crc_open(struct inode *inode, struct file *file)
-{
-       file->private_data = inode->i_private;
-
-       return 0;
-}
-
-static int tegra_sor_crc_release(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
 static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout)
 {
        u32 value;
@@ -615,8 +787,8 @@ static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout)
        timeout = jiffies + msecs_to_jiffies(timeout);
 
        while (time_before(jiffies, timeout)) {
-               value = tegra_sor_readl(sor, SOR_CRC_A);
-               if (value & SOR_CRC_A_VALID)
+               value = tegra_sor_readl(sor, SOR_CRCA);
+               if (value & SOR_CRCA_VALID)
                        return 0;
 
                usleep_range(100, 200);
@@ -625,24 +797,25 @@ static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout)
        return -ETIMEDOUT;
 }
 
-static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer,
-                                 size_t size, loff_t *ppos)
+static int tegra_sor_show_crc(struct seq_file *s, void *data)
 {
-       struct tegra_sor *sor = file->private_data;
-       ssize_t num, err;
-       char buf[10];
+       struct drm_info_node *node = s->private;
+       struct tegra_sor *sor = node->info_ent->data;
+       struct drm_crtc *crtc = sor->output.encoder.crtc;
+       struct drm_device *drm = node->minor->dev;
+       int err = 0;
        u32 value;
 
-       mutex_lock(&sor->lock);
+       drm_modeset_lock_all(drm);
 
-       if (!sor->enabled) {
-               err = -EAGAIN;
+       if (!crtc || !crtc->state->active) {
+               err = -EBUSY;
                goto unlock;
        }
 
-       value = tegra_sor_readl(sor, SOR_STATE_1);
+       value = tegra_sor_readl(sor, SOR_STATE1);
        value &= ~SOR_STATE_ASY_CRC_MODE_MASK;
-       tegra_sor_writel(sor, value, SOR_STATE_1);
+       tegra_sor_writel(sor, value, SOR_STATE1);
 
        value = tegra_sor_readl(sor, SOR_CRC_CNTRL);
        value |= SOR_CRC_CNTRL_ENABLE;
@@ -656,65 +829,66 @@ static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer,
        if (err < 0)
                goto unlock;
 
-       tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A);
-       value = tegra_sor_readl(sor, SOR_CRC_B);
-
-       num = scnprintf(buf, sizeof(buf), "%08x\n", value);
+       tegra_sor_writel(sor, SOR_CRCA_RESET, SOR_CRCA);
+       value = tegra_sor_readl(sor, SOR_CRCB);
 
-       err = simple_read_from_buffer(buffer, size, ppos, buf, num);
+       seq_printf(s, "%08x\n", value);
 
 unlock:
-       mutex_unlock(&sor->lock);
+       drm_modeset_unlock_all(drm);
        return err;
 }
 
-static const struct file_operations tegra_sor_crc_fops = {
-       .owner = THIS_MODULE,
-       .open = tegra_sor_crc_open,
-       .read = tegra_sor_crc_read,
-       .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;
+       struct drm_crtc *crtc = sor->output.encoder.crtc;
+       struct drm_device *drm = node->minor->dev;
+       int err = 0;
+
+       drm_modeset_lock_all(drm);
+
+       if (!crtc || !crtc->state->active) {
+               err = -EBUSY;
+               goto unlock;
+       }
 
 #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_SUPER_STATE0);
+       DUMP_REG(SOR_SUPER_STATE1);
+       DUMP_REG(SOR_STATE0);
+       DUMP_REG(SOR_STATE1);
+       DUMP_REG(SOR_HEAD_STATE0(0));
+       DUMP_REG(SOR_HEAD_STATE0(1));
+       DUMP_REG(SOR_HEAD_STATE1(0));
+       DUMP_REG(SOR_HEAD_STATE1(1));
+       DUMP_REG(SOR_HEAD_STATE2(0));
+       DUMP_REG(SOR_HEAD_STATE2(1));
+       DUMP_REG(SOR_HEAD_STATE3(0));
+       DUMP_REG(SOR_HEAD_STATE3(1));
+       DUMP_REG(SOR_HEAD_STATE4(0));
+       DUMP_REG(SOR_HEAD_STATE4(1));
+       DUMP_REG(SOR_HEAD_STATE5(0));
+       DUMP_REG(SOR_HEAD_STATE5(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_PLL0);
+       DUMP_REG(SOR_PLL1);
+       DUMP_REG(SOR_PLL2);
+       DUMP_REG(SOR_PLL3);
        DUMP_REG(SOR_CSTM);
        DUMP_REG(SOR_LVDS);
-       DUMP_REG(SOR_CRC_A);
-       DUMP_REG(SOR_CRC_B);
+       DUMP_REG(SOR_CRCA);
+       DUMP_REG(SOR_CRCB);
        DUMP_REG(SOR_BLANK);
        DUMP_REG(SOR_SEQ_CTL);
        DUMP_REG(SOR_LANE_SEQ_CTL);
@@ -736,86 +910,89 @@ static int tegra_sor_show_regs(struct seq_file *s, void *data)
        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_VCRC_A0);
+       DUMP_REG(SOR_VCRC_A1);
+       DUMP_REG(SOR_VCRC_B0);
+       DUMP_REG(SOR_VCRC_B1);
+       DUMP_REG(SOR_CCRC_A0);
+       DUMP_REG(SOR_CCRC_A1);
+       DUMP_REG(SOR_CCRC_B0);
+       DUMP_REG(SOR_CCRC_B1);
+       DUMP_REG(SOR_EDATA_A0);
+       DUMP_REG(SOR_EDATA_A1);
+       DUMP_REG(SOR_EDATA_B0);
+       DUMP_REG(SOR_EDATA_B1);
+       DUMP_REG(SOR_COUNT_A0);
+       DUMP_REG(SOR_COUNT_A1);
+       DUMP_REG(SOR_COUNT_B0);
+       DUMP_REG(SOR_COUNT_B1);
+       DUMP_REG(SOR_DEBUG_A0);
+       DUMP_REG(SOR_DEBUG_A1);
+       DUMP_REG(SOR_DEBUG_B0);
+       DUMP_REG(SOR_DEBUG_B1);
        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_LINKCTL0);
+       DUMP_REG(SOR_DP_LINKCTL1);
+       DUMP_REG(SOR_LANE_DRIVE_CURRENT0);
+       DUMP_REG(SOR_LANE_DRIVE_CURRENT1);
+       DUMP_REG(SOR_LANE4_DRIVE_CURRENT0);
+       DUMP_REG(SOR_LANE4_DRIVE_CURRENT1);
+       DUMP_REG(SOR_LANE_PREEMPHASIS0);
+       DUMP_REG(SOR_LANE_PREEMPHASIS1);
+       DUMP_REG(SOR_LANE4_PREEMPHASIS0);
+       DUMP_REG(SOR_LANE4_PREEMPHASIS1);
+       DUMP_REG(SOR_LANE_POSTCURSOR0);
+       DUMP_REG(SOR_LANE_POSTCURSOR1);
+       DUMP_REG(SOR_DP_CONFIG0);
+       DUMP_REG(SOR_DP_CONFIG1);
+       DUMP_REG(SOR_DP_MN0);
+       DUMP_REG(SOR_DP_MN1);
+       DUMP_REG(SOR_DP_PADCTL0);
+       DUMP_REG(SOR_DP_PADCTL1);
+       DUMP_REG(SOR_DP_DEBUG0);
+       DUMP_REG(SOR_DP_DEBUG1);
+       DUMP_REG(SOR_DP_SPARE0);
+       DUMP_REG(SOR_DP_SPARE1);
        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_GENERIC_INFOFRAME_SUBPACK0);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK1);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK2);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK3);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK4);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK5);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK6);
        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);
+       DUMP_REG(SOR_DP_LQ_CSTM0);
+       DUMP_REG(SOR_DP_LQ_CSTM1);
+       DUMP_REG(SOR_DP_LQ_CSTM2);
 
 #undef DUMP_REG
 
-       return 0;
+unlock:
+       drm_modeset_unlock_all(drm);
+       return err;
 }
 
 static const struct drm_info_list debugfs_files[] = {
+       { "crc", tegra_sor_show_crc, 0, NULL },
        { "regs", tegra_sor_show_regs, 0, NULL },
 };
 
 static int tegra_sor_debugfs_init(struct tegra_sor *sor,
                                  struct drm_minor *minor)
 {
-       struct dentry *entry;
+       const char *name = sor->soc->supports_dp ? "sor1" : "sor";
        unsigned int i;
-       int err = 0;
+       int err;
 
-       sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root);
+       sor->debugfs = debugfs_create_dir(name, minor->debugfs_root);
        if (!sor->debugfs)
                return -ENOMEM;
 
@@ -835,14 +1012,9 @@ static int tegra_sor_debugfs_init(struct tegra_sor *sor,
        if (err < 0)
                goto free;
 
-       entry = debugfs_create_file("crc", 0644, sor->debugfs, sor,
-                                   &tegra_sor_crc_fops);
-       if (!entry) {
-               err = -ENOMEM;
-               goto free;
-       }
+       sor->minor = minor;
 
-       return err;
+       return 0;
 
 free:
        kfree(sor->debugfs_files);
@@ -860,14 +1032,10 @@ static void tegra_sor_debugfs_exit(struct tegra_sor *sor)
        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)
-{
+       debugfs_remove_recursive(sor->debugfs);
+       sor->debugfs = NULL;
 }
 
 static enum drm_connector_status
@@ -879,11 +1047,11 @@ tegra_sor_connector_detect(struct drm_connector *connector, bool force)
        if (sor->dpaux)
                return tegra_dpaux_detect(sor->dpaux);
 
-       return connector_status_unknown;
+       return tegra_output_connector_detect(connector, force);
 }
 
 static const struct drm_connector_funcs tegra_sor_connector_funcs = {
-       .dpms = tegra_sor_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .reset = drm_atomic_helper_connector_reset,
        .detect = tegra_sor_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@ -926,22 +1094,102 @@ static const struct drm_encoder_funcs tegra_sor_encoder_funcs = {
        .destroy = tegra_output_encoder_destroy,
 };
 
-static void tegra_sor_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void tegra_sor_edp_disable(struct drm_encoder *encoder)
 {
-}
+       struct tegra_output *output = encoder_to_output(encoder);
+       struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+       struct tegra_sor *sor = to_sor(output);
+       u32 value;
+       int err;
 
-static void tegra_sor_encoder_prepare(struct drm_encoder *encoder)
-{
+       if (output->panel)
+               drm_panel_disable(output->panel);
+
+       err = tegra_sor_detach(sor);
+       if (err < 0)
+               dev_err(sor->dev, "failed to detach SOR: %d\n", err);
+
+       tegra_sor_writel(sor, 0, SOR_STATE1);
+       tegra_sor_update(sor);
+
+       /*
+        * The following accesses registers of the display controller, so make
+        * sure it's only executed when the output is attached to one.
+        */
+       if (dc) {
+               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+               value &= ~SOR_ENABLE;
+               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+               tegra_dc_commit(dc);
+       }
+
+       err = tegra_sor_power_down(sor);
+       if (err < 0)
+               dev_err(sor->dev, "failed to power down SOR: %d\n", err);
+
+       if (sor->dpaux) {
+               err = tegra_dpaux_disable(sor->dpaux);
+               if (err < 0)
+                       dev_err(sor->dev, "failed to disable DP: %d\n", err);
+       }
+
+       err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS);
+       if (err < 0)
+               dev_err(sor->dev, "failed to power off I/O rail: %d\n", err);
+
+       if (output->panel)
+               drm_panel_unprepare(output->panel);
+
+       reset_control_assert(sor->rst);
+       clk_disable_unprepare(sor->clk);
 }
 
-static void tegra_sor_encoder_commit(struct drm_encoder *encoder)
+#if 0
+static int calc_h_ref_to_sync(const struct drm_display_mode *mode,
+                             unsigned int *value)
 {
+       unsigned int hfp, hsw, hbp, a = 0, b;
+
+       hfp = mode->hsync_start - mode->hdisplay;
+       hsw = mode->hsync_end - mode->hsync_start;
+       hbp = mode->htotal - mode->hsync_end;
+
+       pr_info("hfp: %u, hsw: %u, hbp: %u\n", hfp, hsw, hbp);
+
+       b = hfp - 1;
+
+       pr_info("a: %u, b: %u\n", a, b);
+       pr_info("a + hsw + hbp = %u\n", a + hsw + hbp);
+
+       if (a + hsw + hbp <= 11) {
+               a = 1 + 11 - hsw - hbp;
+               pr_info("a: %u\n", a);
+       }
+
+       if (a > b)
+               return -EINVAL;
+
+       if (hsw < 1)
+               return -EINVAL;
+
+       if (mode->hdisplay < 16)
+               return -EINVAL;
+
+       if (value) {
+               if (b > a && a % 2)
+                       *value = a + 1;
+               else
+                       *value = a;
+       }
+
+       return 0;
 }
+#endif
 
-static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
-                                      struct drm_display_mode *mode,
-                                      struct drm_display_mode *adjusted)
+static void tegra_sor_edp_enable(struct drm_encoder *encoder)
 {
+       struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
        struct tegra_output *output = encoder_to_output(encoder);
        struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
        unsigned int vbe, vse, hbe, hse, vbs, hbs, i;
@@ -952,14 +1200,9 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
        int err = 0;
        u32 value;
 
-       mutex_lock(&sor->lock);
-
-       if (sor->enabled)
-               goto unlock;
-
        err = clk_prepare_enable(sor->clk);
        if (err < 0)
-               goto unlock;
+               dev_err(sor->dev, "failed to enable clock: %d\n", err);
 
        reset_control_deassert(sor->rst);
 
@@ -978,7 +1221,7 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
                if (err < 0) {
                        dev_err(sor->dev, "failed to probe eDP link: %d\n",
                                err);
-                       goto unlock;
+                       return;
                }
        }
 
@@ -999,40 +1242,40 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
        value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK;
        tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
 
-       value = tegra_sor_readl(sor, SOR_PLL_2);
-       value &= ~SOR_PLL_2_BANDGAP_POWERDOWN;
-       tegra_sor_writel(sor, value, SOR_PLL_2);
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value &= ~SOR_PLL2_BANDGAP_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL2);
        usleep_range(20, 100);
 
-       value = tegra_sor_readl(sor, SOR_PLL_3);
-       value |= SOR_PLL_3_PLL_VDD_MODE_V3_3;
-       tegra_sor_writel(sor, value, SOR_PLL_3);
+       value = tegra_sor_readl(sor, SOR_PLL3);
+       value |= SOR_PLL3_PLL_VDD_MODE_3V3;
+       tegra_sor_writel(sor, value, SOR_PLL3);
 
-       value = SOR_PLL_0_ICHPMP(0xf) | SOR_PLL_0_VCOCAP_RST |
-               SOR_PLL_0_PLLREG_LEVEL_V45 | SOR_PLL_0_RESISTOR_EXT;
-       tegra_sor_writel(sor, value, SOR_PLL_0);
+       value = SOR_PLL0_ICHPMP(0xf) | SOR_PLL0_VCOCAP_RST |
+               SOR_PLL0_PLLREG_LEVEL_V45 | SOR_PLL0_RESISTOR_EXT;
+       tegra_sor_writel(sor, value, SOR_PLL0);
 
-       value = tegra_sor_readl(sor, SOR_PLL_2);
-       value |= SOR_PLL_2_SEQ_PLLCAPPD;
-       value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
-       value |= SOR_PLL_2_LVDS_ENABLE;
-       tegra_sor_writel(sor, value, SOR_PLL_2);
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value |= SOR_PLL2_SEQ_PLLCAPPD;
+       value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE;
+       value |= SOR_PLL2_LVDS_ENABLE;
+       tegra_sor_writel(sor, value, SOR_PLL2);
 
-       value = SOR_PLL_1_TERM_COMPOUT | SOR_PLL_1_TMDS_TERM;
-       tegra_sor_writel(sor, value, SOR_PLL_1);
+       value = SOR_PLL1_TERM_COMPOUT | SOR_PLL1_TMDS_TERM;
+       tegra_sor_writel(sor, value, SOR_PLL1);
 
        while (true) {
-               value = tegra_sor_readl(sor, SOR_PLL_2);
-               if ((value & SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE) == 0)
+               value = tegra_sor_readl(sor, SOR_PLL2);
+               if ((value & SOR_PLL2_SEQ_PLLCAPPD_ENFORCE) == 0)
                        break;
 
                usleep_range(250, 1000);
        }
 
-       value = tegra_sor_readl(sor, SOR_PLL_2);
-       value &= ~SOR_PLL_2_POWERDOWN_OVERRIDE;
-       value &= ~SOR_PLL_2_PORT_POWERDOWN;
-       tegra_sor_writel(sor, value, SOR_PLL_2);
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value &= ~SOR_PLL2_POWERDOWN_OVERRIDE;
+       value &= ~SOR_PLL2_PORT_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL2);
 
        /*
         * power up
@@ -1045,51 +1288,49 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
        tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
 
        /* step 1 */
-       value = tegra_sor_readl(sor, SOR_PLL_2);
-       value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL_2_PORT_POWERDOWN |
-                SOR_PLL_2_BANDGAP_POWERDOWN;
-       tegra_sor_writel(sor, value, SOR_PLL_2);
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value |= SOR_PLL2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL2_PORT_POWERDOWN |
+                SOR_PLL2_BANDGAP_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL2);
 
-       value = tegra_sor_readl(sor, SOR_PLL_0);
-       value |= SOR_PLL_0_VCOPD | SOR_PLL_0_POWER_OFF;
-       tegra_sor_writel(sor, value, SOR_PLL_0);
+       value = tegra_sor_readl(sor, SOR_PLL0);
+       value |= SOR_PLL0_VCOPD | SOR_PLL0_PWR;
+       tegra_sor_writel(sor, value, SOR_PLL0);
 
-       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
        value &= ~SOR_DP_PADCTL_PAD_CAL_PD;
-       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
 
        /* step 2 */
        err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS);
-       if (err < 0) {
+       if (err < 0)
                dev_err(sor->dev, "failed to power on I/O rail: %d\n", err);
-               goto unlock;
-       }
 
        usleep_range(5, 100);
 
        /* step 3 */
-       value = tegra_sor_readl(sor, SOR_PLL_2);
-       value &= ~SOR_PLL_2_BANDGAP_POWERDOWN;
-       tegra_sor_writel(sor, value, SOR_PLL_2);
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value &= ~SOR_PLL2_BANDGAP_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL2);
 
        usleep_range(20, 100);
 
        /* step 4 */
-       value = tegra_sor_readl(sor, SOR_PLL_0);
-       value &= ~SOR_PLL_0_POWER_OFF;
-       value &= ~SOR_PLL_0_VCOPD;
-       tegra_sor_writel(sor, value, SOR_PLL_0);
+       value = tegra_sor_readl(sor, SOR_PLL0);
+       value &= ~SOR_PLL0_VCOPD;
+       value &= ~SOR_PLL0_PWR;
+       tegra_sor_writel(sor, value, SOR_PLL0);
 
-       value = tegra_sor_readl(sor, SOR_PLL_2);
-       value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
-       tegra_sor_writel(sor, value, SOR_PLL_2);
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE;
+       tegra_sor_writel(sor, value, SOR_PLL2);
 
        usleep_range(200, 1000);
 
        /* step 5 */
-       value = tegra_sor_readl(sor, SOR_PLL_2);
-       value &= ~SOR_PLL_2_PORT_POWERDOWN;
-       tegra_sor_writel(sor, value, SOR_PLL_2);
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value &= ~SOR_PLL2_PORT_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL2);
 
        /* switch to DP clock */
        err = clk_set_parent(sor->clk, sor->clk_dp);
@@ -1097,7 +1338,7 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
                dev_err(sor->dev, "failed to set DP parent clock: %d\n", err);
 
        /* power DP lanes */
-       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
 
        if (link.num_lanes <= 2)
                value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2);
@@ -1114,12 +1355,12 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
        else
                value |= SOR_DP_PADCTL_PD_TXD_0;
 
-       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
 
-       value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0);
+       value = tegra_sor_readl(sor, SOR_DP_LINKCTL0);
        value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK;
        value |= SOR_DP_LINKCTL_LANE_COUNT(link.num_lanes);
-       tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0);
+       tegra_sor_writel(sor, value, SOR_DP_LINKCTL0);
 
        /* start lane sequencer */
        value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN |
@@ -1141,14 +1382,14 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
        tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
 
        /* set linkctl */
-       value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0);
+       value = tegra_sor_readl(sor, SOR_DP_LINKCTL0);
        value |= SOR_DP_LINKCTL_ENABLE;
 
        value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK;
        value |= SOR_DP_LINKCTL_TU_SIZE(config.tu_size);
 
        value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
-       tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0);
+       tegra_sor_writel(sor, value, SOR_DP_LINKCTL0);
 
        for (i = 0, value = 0; i < 4; i++) {
                unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
@@ -1159,7 +1400,7 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
 
        tegra_sor_writel(sor, value, SOR_DP_TPG);
 
-       value = tegra_sor_readl(sor, SOR_DP_CONFIG_0);
+       value = tegra_sor_readl(sor, SOR_DP_CONFIG0);
        value &= ~SOR_DP_CONFIG_WATERMARK_MASK;
        value |= SOR_DP_CONFIG_WATERMARK(config.watermark);
 
@@ -1176,7 +1417,7 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
 
        value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE;
        value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE;
-       tegra_sor_writel(sor, value, SOR_DP_CONFIG_0);
+       tegra_sor_writel(sor, value, SOR_DP_CONFIG0);
 
        value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS);
        value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK;
@@ -1189,33 +1430,27 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
        tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS);
 
        /* enable pad calibration logic */
-       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
        value |= SOR_DP_PADCTL_PAD_CAL_PD;
-       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
 
        if (sor->dpaux) {
                u8 rate, lanes;
 
                err = drm_dp_link_probe(aux, &link);
-               if (err < 0) {
+               if (err < 0)
                        dev_err(sor->dev, "failed to probe eDP link: %d\n",
                                err);
-                       goto unlock;
-               }
 
                err = drm_dp_link_power_up(aux, &link);
-               if (err < 0) {
+               if (err < 0)
                        dev_err(sor->dev, "failed to power up eDP link: %d\n",
                                err);
-                       goto unlock;
-               }
 
                err = drm_dp_link_configure(aux, &link);
-               if (err < 0) {
+               if (err < 0)
                        dev_err(sor->dev, "failed to configure eDP link: %d\n",
                                err);
-                       goto unlock;
-               }
 
                rate = drm_dp_link_rate_to_bw_code(link.rate);
                lanes = link.num_lanes;
@@ -1225,14 +1460,14 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
                value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate);
                tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
 
-               value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0);
+               value = tegra_sor_readl(sor, SOR_DP_LINKCTL0);
                value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK;
                value |= SOR_DP_LINKCTL_LANE_COUNT(lanes);
 
                if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
                        value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
 
-               tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0);
+               tegra_sor_writel(sor, value, SOR_DP_LINKCTL0);
 
                /* disable training pattern generator */
 
@@ -1249,17 +1484,14 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
                if (err < 0) {
                        dev_err(sor->dev, "DP fast link training failed: %d\n",
                                err);
-                       goto unlock;
                }
 
                dev_dbg(sor->dev, "fast link training succeeded\n");
        }
 
        err = tegra_sor_power_up(sor, 250);
-       if (err < 0) {
+       if (err < 0)
                dev_err(sor->dev, "failed to power up SOR: %d\n", err);
-               goto unlock;
-       }
 
        /*
         * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete
@@ -1295,7 +1527,7 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
                break;
        }
 
-       tegra_sor_writel(sor, value, SOR_STATE_1);
+       tegra_sor_writel(sor, value, SOR_STATE1);
 
        /*
         * TODO: The video timing programming below doesn't seem to match the
@@ -1303,25 +1535,27 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
         */
 
        value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff);
-       tegra_sor_writel(sor, value, SOR_HEAD_STATE_1(0));
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE1(dc->pipe));
 
        vse = mode->vsync_end - mode->vsync_start - 1;
        hse = mode->hsync_end - mode->hsync_start - 1;
 
        value = ((vse & 0x7fff) << 16) | (hse & 0x7fff);
-       tegra_sor_writel(sor, value, SOR_HEAD_STATE_2(0));
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE2(dc->pipe));
 
        vbe = vse + (mode->vsync_start - mode->vdisplay);
        hbe = hse + (mode->hsync_start - mode->hdisplay);
 
        value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff);
-       tegra_sor_writel(sor, value, SOR_HEAD_STATE_3(0));
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE3(dc->pipe));
 
        vbs = vbe + mode->vdisplay;
        hbs = hbe + mode->hdisplay;
 
        value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff);
-       tegra_sor_writel(sor, value, SOR_HEAD_STATE_4(0));
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE4(dc->pipe));
+
+       tegra_sor_writel(sor, 0x1, SOR_HEAD_STATE5(dc->pipe));
 
        /* CSTM (LVDS, link A/B, upper) */
        value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_A | SOR_CSTM_LINK_ACT_B |
@@ -1330,10 +1564,8 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
 
        /* PWM setup */
        err = tegra_sor_setup_pwm(sor, 250);
-       if (err < 0) {
+       if (err < 0)
                dev_err(sor->dev, "failed to setup PWM: %d\n", err);
-               goto unlock;
-       }
 
        tegra_sor_update(sor);
 
@@ -1344,93 +1576,15 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
        tegra_dc_commit(dc);
 
        err = tegra_sor_attach(sor);
-       if (err < 0) {
+       if (err < 0)
                dev_err(sor->dev, "failed to attach SOR: %d\n", err);
-               goto unlock;
-       }
 
        err = tegra_sor_wakeup(sor);
-       if (err < 0) {
+       if (err < 0)
                dev_err(sor->dev, "failed to enable DC: %d\n", err);
-               goto unlock;
-       }
 
        if (output->panel)
                drm_panel_enable(output->panel);
-
-       sor->enabled = true;
-
-unlock:
-       mutex_unlock(&sor->lock);
-}
-
-static void tegra_sor_encoder_disable(struct drm_encoder *encoder)
-{
-       struct tegra_output *output = encoder_to_output(encoder);
-       struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
-       struct tegra_sor *sor = to_sor(output);
-       u32 value;
-       int err;
-
-       mutex_lock(&sor->lock);
-
-       if (!sor->enabled)
-               goto unlock;
-
-       if (output->panel)
-               drm_panel_disable(output->panel);
-
-       err = tegra_sor_detach(sor);
-       if (err < 0) {
-               dev_err(sor->dev, "failed to detach SOR: %d\n", err);
-               goto unlock;
-       }
-
-       tegra_sor_writel(sor, 0, SOR_STATE_1);
-       tegra_sor_update(sor);
-
-       /*
-        * The following accesses registers of the display controller, so make
-        * sure it's only executed when the output is attached to one.
-        */
-       if (dc) {
-               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
-               value &= ~SOR_ENABLE;
-               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
-
-               tegra_dc_commit(dc);
-       }
-
-       err = tegra_sor_power_down(sor);
-       if (err < 0) {
-               dev_err(sor->dev, "failed to power down SOR: %d\n", err);
-               goto unlock;
-       }
-
-       if (sor->dpaux) {
-               err = tegra_dpaux_disable(sor->dpaux);
-               if (err < 0) {
-                       dev_err(sor->dev, "failed to disable DP: %d\n", err);
-                       goto unlock;
-               }
-       }
-
-       err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS);
-       if (err < 0) {
-               dev_err(sor->dev, "failed to power off I/O rail: %d\n", err);
-               goto unlock;
-       }
-
-       if (output->panel)
-               drm_panel_unprepare(output->panel);
-
-       clk_disable_unprepare(sor->clk);
-       reset_control_assert(sor->rst);
-
-       sor->enabled = false;
-
-unlock:
-       mutex_unlock(&sor->lock);
 }
 
 static int
@@ -1454,41 +1608,582 @@ tegra_sor_encoder_atomic_check(struct drm_encoder *encoder,
        return 0;
 }
 
-static const struct drm_encoder_helper_funcs tegra_sor_encoder_helper_funcs = {
-       .dpms = tegra_sor_encoder_dpms,
-       .prepare = tegra_sor_encoder_prepare,
-       .commit = tegra_sor_encoder_commit,
-       .mode_set = tegra_sor_encoder_mode_set,
-       .disable = tegra_sor_encoder_disable,
+static const struct drm_encoder_helper_funcs tegra_sor_edp_helpers = {
+       .disable = tegra_sor_edp_disable,
+       .enable = tegra_sor_edp_enable,
        .atomic_check = tegra_sor_encoder_atomic_check,
 };
 
-static int tegra_sor_init(struct host1x_client *client)
+static inline u32 tegra_sor_hdmi_subpack(const u8 *ptr, size_t size)
 {
-       struct drm_device *drm = dev_get_drvdata(client->parent);
-       struct tegra_sor *sor = host1x_client_to_sor(client);
-       int err;
+       u32 value = 0;
+       size_t i;
 
-       if (!sor->dpaux)
-               return -ENODEV;
+       for (i = size; i > 0; i--)
+               value = (value << 8) | ptr[i - 1];
 
-       sor->output.dev = sor->dev;
+       return value;
+}
 
-       drm_connector_init(drm, &sor->output.connector,
-                          &tegra_sor_connector_funcs,
-                          DRM_MODE_CONNECTOR_eDP);
-       drm_connector_helper_add(&sor->output.connector,
-                                &tegra_sor_connector_helper_funcs);
-       sor->output.connector.dpms = DRM_MODE_DPMS_OFF;
+static void tegra_sor_hdmi_write_infopack(struct tegra_sor *sor,
+                                         const void *data, size_t size)
+{
+       const u8 *ptr = data;
+       unsigned long offset;
+       size_t i, j;
+       u32 value;
 
-       drm_encoder_init(drm, &sor->output.encoder, &tegra_sor_encoder_funcs,
-                        DRM_MODE_ENCODER_TMDS);
-       drm_encoder_helper_add(&sor->output.encoder,
-                              &tegra_sor_encoder_helper_funcs);
+       switch (ptr[0]) {
+       case HDMI_INFOFRAME_TYPE_AVI:
+               offset = SOR_HDMI_AVI_INFOFRAME_HEADER;
+               break;
 
-       drm_mode_connector_attach_encoder(&sor->output.connector,
-                                         &sor->output.encoder);
-       drm_connector_register(&sor->output.connector);
+       case HDMI_INFOFRAME_TYPE_AUDIO:
+               offset = SOR_HDMI_AUDIO_INFOFRAME_HEADER;
+               break;
+
+       case HDMI_INFOFRAME_TYPE_VENDOR:
+               offset = SOR_HDMI_VSI_INFOFRAME_HEADER;
+               break;
+
+       default:
+               dev_err(sor->dev, "unsupported infoframe type: %02x\n",
+                       ptr[0]);
+               return;
+       }
+
+       value = INFOFRAME_HEADER_TYPE(ptr[0]) |
+               INFOFRAME_HEADER_VERSION(ptr[1]) |
+               INFOFRAME_HEADER_LEN(ptr[2]);
+       tegra_sor_writel(sor, value, offset);
+       offset++;
+
+       /*
+        * Each subpack contains 7 bytes, divided into:
+        * - subpack_low: bytes 0 - 3
+        * - subpack_high: bytes 4 - 6 (with byte 7 padded to 0x00)
+        */
+       for (i = 3, j = 0; i < size; i += 7, j += 8) {
+               size_t rem = size - i, num = min_t(size_t, rem, 4);
+
+               value = tegra_sor_hdmi_subpack(&ptr[i], num);
+               tegra_sor_writel(sor, value, offset++);
+
+               num = min_t(size_t, rem - num, 3);
+
+               value = tegra_sor_hdmi_subpack(&ptr[i + 4], num);
+               tegra_sor_writel(sor, value, offset++);
+       }
+}
+
+static int
+tegra_sor_hdmi_setup_avi_infoframe(struct tegra_sor *sor,
+                                  const struct drm_display_mode *mode)
+{
+       u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
+       struct hdmi_avi_infoframe frame;
+       u32 value;
+       int err;
+
+       /* disable AVI infoframe */
+       value = tegra_sor_readl(sor, SOR_HDMI_AVI_INFOFRAME_CTRL);
+       value &= ~INFOFRAME_CTRL_SINGLE;
+       value &= ~INFOFRAME_CTRL_OTHER;
+       value &= ~INFOFRAME_CTRL_ENABLE;
+       tegra_sor_writel(sor, value, SOR_HDMI_AVI_INFOFRAME_CTRL);
+
+       err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to setup AVI infoframe: %d\n", err);
+               return err;
+       }
+
+       err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
+       if (err < 0) {
+               dev_err(sor->dev, "failed to pack AVI infoframe: %d\n", err);
+               return err;
+       }
+
+       tegra_sor_hdmi_write_infopack(sor, buffer, err);
+
+       /* enable AVI infoframe */
+       value = tegra_sor_readl(sor, SOR_HDMI_AVI_INFOFRAME_CTRL);
+       value |= INFOFRAME_CTRL_CHECKSUM_ENABLE;
+       value |= INFOFRAME_CTRL_ENABLE;
+       tegra_sor_writel(sor, value, SOR_HDMI_AVI_INFOFRAME_CTRL);
+
+       return 0;
+}
+
+static void tegra_sor_hdmi_disable_audio_infoframe(struct tegra_sor *sor)
+{
+       u32 value;
+
+       value = tegra_sor_readl(sor, SOR_HDMI_AUDIO_INFOFRAME_CTRL);
+       value &= ~INFOFRAME_CTRL_ENABLE;
+       tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_INFOFRAME_CTRL);
+}
+
+static struct tegra_sor_hdmi_settings *
+tegra_sor_hdmi_find_settings(struct tegra_sor *sor, unsigned long frequency)
+{
+       unsigned int i;
+
+       for (i = 0; i < sor->num_settings; i++)
+               if (frequency <= sor->settings[i].frequency)
+                       return &sor->settings[i];
+
+       return NULL;
+}
+
+static void tegra_sor_hdmi_disable(struct drm_encoder *encoder)
+{
+       struct tegra_output *output = encoder_to_output(encoder);
+       struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+       struct tegra_sor *sor = to_sor(output);
+       u32 value;
+       int err;
+
+       err = tegra_sor_detach(sor);
+       if (err < 0)
+               dev_err(sor->dev, "failed to detach SOR: %d\n", err);
+
+       tegra_sor_writel(sor, 0, SOR_STATE1);
+       tegra_sor_update(sor);
+
+       /* disable display to SOR clock */
+       value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+       value &= ~SOR1_TIMING_CYA;
+       value &= ~SOR1_ENABLE;
+       tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+       tegra_dc_commit(dc);
+
+       err = tegra_sor_power_down(sor);
+       if (err < 0)
+               dev_err(sor->dev, "failed to power down SOR: %d\n", err);
+
+       err = tegra_io_rail_power_off(TEGRA_IO_RAIL_HDMI);
+       if (err < 0)
+               dev_err(sor->dev, "failed to power off HDMI rail: %d\n", err);
+
+       reset_control_assert(sor->rst);
+       usleep_range(1000, 2000);
+       clk_disable_unprepare(sor->clk);
+}
+
+static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
+{
+       struct tegra_output *output = encoder_to_output(encoder);
+       unsigned int h_ref_to_sync = 1, pulse_start, max_ac;
+       struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+       unsigned int vbe, vse, hbe, hse, vbs, hbs, div;
+       struct tegra_sor_hdmi_settings *settings;
+       struct tegra_sor *sor = to_sor(output);
+       struct drm_display_mode *mode;
+       struct drm_display_info *info;
+       u32 value;
+       int err;
+
+       mode = &encoder->crtc->state->adjusted_mode;
+       info = &output->connector.display_info;
+
+       err = clk_prepare_enable(sor->clk);
+       if (err < 0)
+               dev_err(sor->dev, "failed to enable clock: %d\n", err);
+
+       usleep_range(1000, 2000);
+
+       reset_control_deassert(sor->rst);
+
+       err = clk_set_parent(sor->clk, sor->clk_safe);
+       if (err < 0)
+               dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
+
+       div = clk_get_rate(sor->clk) / 1000000 * 4;
+
+       err = tegra_io_rail_power_on(TEGRA_IO_RAIL_HDMI);
+       if (err < 0)
+               dev_err(sor->dev, "failed to power on HDMI rail: %d\n", err);
+
+       usleep_range(20, 100);
+
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value &= ~SOR_PLL2_BANDGAP_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL2);
+
+       usleep_range(20, 100);
+
+       value = tegra_sor_readl(sor, SOR_PLL3);
+       value &= ~SOR_PLL3_PLL_VDD_MODE_3V3;
+       tegra_sor_writel(sor, value, SOR_PLL3);
+
+       value = tegra_sor_readl(sor, SOR_PLL0);
+       value &= ~SOR_PLL0_VCOPD;
+       value &= ~SOR_PLL0_PWR;
+       tegra_sor_writel(sor, value, SOR_PLL0);
+
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE;
+       tegra_sor_writel(sor, value, SOR_PLL2);
+
+       usleep_range(200, 400);
+
+       value = tegra_sor_readl(sor, SOR_PLL2);
+       value &= ~SOR_PLL2_POWERDOWN_OVERRIDE;
+       value &= ~SOR_PLL2_PORT_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL2);
+
+       usleep_range(20, 100);
+
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
+       value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
+                SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2;
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
+
+       while (true) {
+               value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
+               if ((value & SOR_LANE_SEQ_CTL_STATE_BUSY) == 0)
+                       break;
+
+               usleep_range(250, 1000);
+       }
+
+       value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN |
+               SOR_LANE_SEQ_CTL_POWER_STATE_UP | SOR_LANE_SEQ_CTL_DELAY(5);
+       tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL);
+
+       while (true) {
+               value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
+               if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0)
+                       break;
+
+               usleep_range(250, 1000);
+       }
+
+       value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
+       value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
+       value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK;
+
+       if (mode->clock < 340000)
+               value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70;
+       else
+               value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G5_40;
+
+       value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK;
+       tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
+
+       value = tegra_sor_readl(sor, SOR_DP_SPARE0);
+       value |= SOR_DP_SPARE_DISP_VIDEO_PREAMBLE;
+       value &= ~SOR_DP_SPARE_PANEL_INTERNAL;
+       value |= SOR_DP_SPARE_SEQ_ENABLE;
+       tegra_sor_writel(sor, value, SOR_DP_SPARE0);
+
+       value = SOR_SEQ_CTL_PU_PC(0) | SOR_SEQ_CTL_PU_PC_ALT(0) |
+               SOR_SEQ_CTL_PD_PC(8) | SOR_SEQ_CTL_PD_PC_ALT(8);
+       tegra_sor_writel(sor, value, SOR_SEQ_CTL);
+
+       value = SOR_SEQ_INST_DRIVE_PWM_OUT_LO | SOR_SEQ_INST_HALT |
+               SOR_SEQ_INST_WAIT_VSYNC | SOR_SEQ_INST_WAIT(1);
+       tegra_sor_writel(sor, value, SOR_SEQ_INST(0));
+       tegra_sor_writel(sor, value, SOR_SEQ_INST(8));
+
+       /* program the reference clock */
+       value = SOR_REFCLK_DIV_INT(div) | SOR_REFCLK_DIV_FRAC(div);
+       tegra_sor_writel(sor, value, SOR_REFCLK);
+
+       /* XXX don't hardcode */
+       value = SOR_XBAR_CTRL_LINK1_XSEL(4, 4) |
+               SOR_XBAR_CTRL_LINK1_XSEL(3, 3) |
+               SOR_XBAR_CTRL_LINK1_XSEL(2, 2) |
+               SOR_XBAR_CTRL_LINK1_XSEL(1, 1) |
+               SOR_XBAR_CTRL_LINK1_XSEL(0, 0) |
+               SOR_XBAR_CTRL_LINK0_XSEL(4, 4) |
+               SOR_XBAR_CTRL_LINK0_XSEL(3, 3) |
+               SOR_XBAR_CTRL_LINK0_XSEL(2, 0) |
+               SOR_XBAR_CTRL_LINK0_XSEL(1, 1) |
+               SOR_XBAR_CTRL_LINK0_XSEL(0, 2);
+       tegra_sor_writel(sor, value, SOR_XBAR_CTRL);
+
+       tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL);
+
+       err = clk_set_parent(sor->clk, sor->clk_parent);
+       if (err < 0)
+               dev_err(sor->dev, "failed to set parent clock: %d\n", err);
+
+       value = SOR_INPUT_CONTROL_HDMI_SRC_SELECT(dc->pipe);
+
+       /* XXX is this the proper check? */
+       if (mode->clock < 75000)
+               value |= SOR_INPUT_CONTROL_ARM_VIDEO_RANGE_LIMITED;
+
+       tegra_sor_writel(sor, value, SOR_INPUT_CONTROL);
+
+       max_ac = ((mode->htotal - mode->hdisplay) - SOR_REKEY - 18) / 32;
+
+       value = SOR_HDMI_CTRL_ENABLE | SOR_HDMI_CTRL_MAX_AC_PACKET(max_ac) |
+               SOR_HDMI_CTRL_AUDIO_LAYOUT | SOR_HDMI_CTRL_REKEY(SOR_REKEY);
+       tegra_sor_writel(sor, value, SOR_HDMI_CTRL);
+
+       /* H_PULSE2 setup */
+       pulse_start = h_ref_to_sync + (mode->hsync_end - mode->hsync_start) +
+                     (mode->htotal - mode->hsync_end) - 10;
+
+       value = PULSE_LAST_END_A | PULSE_QUAL_VACTIVE |
+               PULSE_POLARITY_HIGH | PULSE_MODE_NORMAL;
+       tegra_dc_writel(dc, value, DC_DISP_H_PULSE2_CONTROL);
+
+       value = PULSE_END(pulse_start + 8) | PULSE_START(pulse_start);
+       tegra_dc_writel(dc, value, DC_DISP_H_PULSE2_POSITION_A);
+
+       value = tegra_dc_readl(dc, DC_DISP_DISP_SIGNAL_OPTIONS0);
+       value |= H_PULSE2_ENABLE;
+       tegra_dc_writel(dc, value, DC_DISP_DISP_SIGNAL_OPTIONS0);
+
+       /* infoframe setup */
+       err = tegra_sor_hdmi_setup_avi_infoframe(sor, mode);
+       if (err < 0)
+               dev_err(sor->dev, "failed to setup AVI infoframe: %d\n", err);
+
+       /* XXX HDMI audio support not implemented yet */
+       tegra_sor_hdmi_disable_audio_infoframe(sor);
+
+       /* use single TMDS protocol */
+       value = tegra_sor_readl(sor, SOR_STATE1);
+       value &= ~SOR_STATE_ASY_PROTOCOL_MASK;
+       value |= SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A;
+       tegra_sor_writel(sor, value, SOR_STATE1);
+
+       /* power up pad calibration */
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
+       value &= ~SOR_DP_PADCTL_PAD_CAL_PD;
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
+
+       /* production settings */
+       settings = tegra_sor_hdmi_find_settings(sor, mode->clock * 1000);
+       if (IS_ERR(settings)) {
+               dev_err(sor->dev, "no settings for pixel clock %d Hz: %ld\n",
+                       mode->clock * 1000, PTR_ERR(settings));
+               return;
+       }
+
+       value = tegra_sor_readl(sor, SOR_PLL0);
+       value &= ~SOR_PLL0_ICHPMP_MASK;
+       value &= ~SOR_PLL0_VCOCAP_MASK;
+       value |= SOR_PLL0_ICHPMP(settings->ichpmp);
+       value |= SOR_PLL0_VCOCAP(settings->vcocap);
+       tegra_sor_writel(sor, value, SOR_PLL0);
+
+       tegra_sor_dp_term_calibrate(sor);
+
+       value = tegra_sor_readl(sor, SOR_PLL1);
+       value &= ~SOR_PLL1_LOADADJ_MASK;
+       value |= SOR_PLL1_LOADADJ(settings->loadadj);
+       tegra_sor_writel(sor, value, SOR_PLL1);
+
+       value = tegra_sor_readl(sor, SOR_PLL3);
+       value &= ~SOR_PLL3_BG_VREF_LEVEL_MASK;
+       value |= SOR_PLL3_BG_VREF_LEVEL(settings->bg_vref);
+       tegra_sor_writel(sor, value, SOR_PLL3);
+
+       value = settings->drive_current[0] << 24 |
+               settings->drive_current[1] << 16 |
+               settings->drive_current[2] <<  8 |
+               settings->drive_current[3] <<  0;
+       tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT0);
+
+       value = settings->preemphasis[0] << 24 |
+               settings->preemphasis[1] << 16 |
+               settings->preemphasis[2] <<  8 |
+               settings->preemphasis[3] <<  0;
+       tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS0);
+
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
+       value &= ~SOR_DP_PADCTL_TX_PU_MASK;
+       value |= SOR_DP_PADCTL_TX_PU_ENABLE;
+       value |= SOR_DP_PADCTL_TX_PU(settings->tx_pu);
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
+
+       /* power down pad calibration */
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
+       value |= SOR_DP_PADCTL_PAD_CAL_PD;
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
+
+       /* miscellaneous display controller settings */
+       value = VSYNC_H_POSITION(1);
+       tegra_dc_writel(dc, value, DC_DISP_DISP_TIMING_OPTIONS);
+
+       value = tegra_dc_readl(dc, DC_DISP_DISP_COLOR_CONTROL);
+       value &= ~DITHER_CONTROL_MASK;
+       value &= ~BASE_COLOR_SIZE_MASK;
+
+       switch (info->bpc) {
+       case 6:
+               value |= BASE_COLOR_SIZE_666;
+               break;
+
+       case 8:
+               value |= BASE_COLOR_SIZE_888;
+               break;
+
+       default:
+               WARN(1, "%u bits-per-color not supported\n", info->bpc);
+               break;
+       }
+
+       tegra_dc_writel(dc, value, DC_DISP_DISP_COLOR_CONTROL);
+
+       err = tegra_sor_power_up(sor, 250);
+       if (err < 0)
+               dev_err(sor->dev, "failed to power up SOR: %d\n", err);
+
+       /* configure mode */
+       value = tegra_sor_readl(sor, SOR_STATE1);
+       value &= ~SOR_STATE_ASY_PIXELDEPTH_MASK;
+       value &= ~SOR_STATE_ASY_CRC_MODE_MASK;
+       value &= ~SOR_STATE_ASY_OWNER_MASK;
+
+       value |= SOR_STATE_ASY_CRC_MODE_COMPLETE |
+                SOR_STATE_ASY_OWNER(dc->pipe + 1);
+
+       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+               value &= ~SOR_STATE_ASY_HSYNCPOL;
+
+       if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+               value |= SOR_STATE_ASY_HSYNCPOL;
+
+       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+               value &= ~SOR_STATE_ASY_VSYNCPOL;
+
+       if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+               value |= SOR_STATE_ASY_VSYNCPOL;
+
+       switch (info->bpc) {
+       case 8:
+               value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444;
+               break;
+
+       case 6:
+               value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444;
+               break;
+
+       default:
+               BUG();
+               break;
+       }
+
+       tegra_sor_writel(sor, value, SOR_STATE1);
+
+       value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe));
+       value &= ~SOR_HEAD_STATE_RANGECOMPRESS_MASK;
+       value &= ~SOR_HEAD_STATE_DYNRANGE_MASK;
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe));
+
+       value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe));
+       value &= ~SOR_HEAD_STATE_COLORSPACE_MASK;
+       value |= SOR_HEAD_STATE_COLORSPACE_RGB;
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe));
+
+       /*
+        * TODO: The video timing programming below doesn't seem to match the
+        * register definitions.
+        */
+
+       value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff);
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE1(dc->pipe));
+
+       /* sync end = sync width - 1 */
+       vse = mode->vsync_end - mode->vsync_start - 1;
+       hse = mode->hsync_end - mode->hsync_start - 1;
+
+       value = ((vse & 0x7fff) << 16) | (hse & 0x7fff);
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE2(dc->pipe));
+
+       /* blank end = sync end + back porch */
+       vbe = vse + (mode->vtotal - mode->vsync_end);
+       hbe = hse + (mode->htotal - mode->hsync_end);
+
+       value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff);
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE3(dc->pipe));
+
+       /* blank start = blank end + active */
+       vbs = vbe + mode->vdisplay;
+       hbs = hbe + mode->hdisplay;
+
+       value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff);
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE4(dc->pipe));
+
+       tegra_sor_writel(sor, 0x1, SOR_HEAD_STATE5(dc->pipe));
+
+       tegra_sor_update(sor);
+
+       err = tegra_sor_attach(sor);
+       if (err < 0)
+               dev_err(sor->dev, "failed to attach SOR: %d\n", err);
+
+       /* enable display to SOR clock and generate HDMI preamble */
+       value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+       value |= SOR1_ENABLE | SOR1_TIMING_CYA;
+       tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+       tegra_dc_commit(dc);
+
+       err = tegra_sor_wakeup(sor);
+       if (err < 0)
+               dev_err(sor->dev, "failed to wakeup SOR: %d\n", err);
+}
+
+static const struct drm_encoder_helper_funcs tegra_sor_hdmi_helpers = {
+       .disable = tegra_sor_hdmi_disable,
+       .enable = tegra_sor_hdmi_enable,
+       .atomic_check = tegra_sor_encoder_atomic_check,
+};
+
+static int tegra_sor_init(struct host1x_client *client)
+{
+       struct drm_device *drm = dev_get_drvdata(client->parent);
+       const struct drm_encoder_helper_funcs *helpers = NULL;
+       struct tegra_sor *sor = host1x_client_to_sor(client);
+       int connector = DRM_MODE_CONNECTOR_Unknown;
+       int encoder = DRM_MODE_ENCODER_NONE;
+       int err;
+
+       if (!sor->dpaux) {
+               if (sor->soc->supports_hdmi) {
+                       connector = DRM_MODE_CONNECTOR_HDMIA;
+                       encoder = DRM_MODE_ENCODER_TMDS;
+                       helpers = &tegra_sor_hdmi_helpers;
+               } else if (sor->soc->supports_lvds) {
+                       connector = DRM_MODE_CONNECTOR_LVDS;
+                       encoder = DRM_MODE_ENCODER_LVDS;
+               }
+       } else {
+               if (sor->soc->supports_edp) {
+                       connector = DRM_MODE_CONNECTOR_eDP;
+                       encoder = DRM_MODE_ENCODER_TMDS;
+                       helpers = &tegra_sor_edp_helpers;
+               } else if (sor->soc->supports_dp) {
+                       connector = DRM_MODE_CONNECTOR_DisplayPort;
+                       encoder = DRM_MODE_ENCODER_TMDS;
+               }
+       }
+
+       sor->output.dev = sor->dev;
+
+       drm_connector_init(drm, &sor->output.connector,
+                          &tegra_sor_connector_funcs,
+                          connector);
+       drm_connector_helper_add(&sor->output.connector,
+                                &tegra_sor_connector_helper_funcs);
+       sor->output.connector.dpms = DRM_MODE_DPMS_OFF;
+
+       drm_encoder_init(drm, &sor->output.encoder, &tegra_sor_encoder_funcs,
+                        encoder);
+       drm_encoder_helper_add(&sor->output.encoder, helpers);
+
+       drm_mode_connector_attach_encoder(&sor->output.connector,
+                                         &sor->output.encoder);
+       drm_connector_register(&sor->output.connector);
 
        err = tegra_output_init(drm, &sor->output);
        if (err < 0) {
@@ -1577,18 +2272,130 @@ static const struct host1x_client_ops sor_client_ops = {
        .exit = tegra_sor_exit,
 };
 
+static const struct tegra_sor_ops tegra_sor_edp_ops = {
+       .name = "eDP",
+};
+
+static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
+{
+       int err;
+
+       sor->avdd_io_supply = devm_regulator_get(sor->dev, "avdd-io");
+       if (IS_ERR(sor->avdd_io_supply)) {
+               dev_err(sor->dev, "cannot get AVDD I/O supply: %ld\n",
+                       PTR_ERR(sor->avdd_io_supply));
+               return PTR_ERR(sor->avdd_io_supply);
+       }
+
+       err = regulator_enable(sor->avdd_io_supply);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to enable AVDD I/O supply: %d\n",
+                       err);
+               return err;
+       }
+
+       sor->vdd_pll_supply = devm_regulator_get(sor->dev, "vdd-pll");
+       if (IS_ERR(sor->vdd_pll_supply)) {
+               dev_err(sor->dev, "cannot get VDD PLL supply: %ld\n",
+                       PTR_ERR(sor->vdd_pll_supply));
+               return PTR_ERR(sor->vdd_pll_supply);
+       }
+
+       err = regulator_enable(sor->vdd_pll_supply);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to enable VDD PLL supply: %d\n",
+                       err);
+               return err;
+       }
+
+       sor->hdmi_supply = devm_regulator_get(sor->dev, "hdmi");
+       if (IS_ERR(sor->hdmi_supply)) {
+               dev_err(sor->dev, "cannot get HDMI supply: %ld\n",
+                       PTR_ERR(sor->hdmi_supply));
+               return PTR_ERR(sor->hdmi_supply);
+       }
+
+       err = regulator_enable(sor->hdmi_supply);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to enable HDMI supply: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static int tegra_sor_hdmi_remove(struct tegra_sor *sor)
+{
+       regulator_disable(sor->hdmi_supply);
+       regulator_disable(sor->vdd_pll_supply);
+       regulator_disable(sor->avdd_io_supply);
+
+       return 0;
+}
+
+static const struct tegra_sor_ops tegra_sor_hdmi_ops = {
+       .name = "HDMI",
+       .probe = tegra_sor_hdmi_probe,
+       .remove = tegra_sor_hdmi_remove,
+};
+
+static const struct tegra_sor_soc tegra124_sor = {
+       .supports_edp = true,
+       .supports_lvds = true,
+       .supports_hdmi = false,
+       .supports_dp = false,
+};
+
+static const struct tegra_sor_soc tegra210_sor = {
+       .supports_edp = true,
+       .supports_lvds = false,
+       .supports_hdmi = false,
+       .supports_dp = false,
+};
+
+static const struct tegra_sor_soc tegra210_sor1 = {
+       .supports_edp = false,
+       .supports_lvds = false,
+       .supports_hdmi = true,
+       .supports_dp = true,
+
+       .num_settings = ARRAY_SIZE(tegra210_sor_hdmi_defaults),
+       .settings = tegra210_sor_hdmi_defaults,
+};
+
+static const struct of_device_id tegra_sor_of_match[] = {
+       { .compatible = "nvidia,tegra210-sor1", .data = &tegra210_sor1 },
+       { .compatible = "nvidia,tegra210-sor", .data = &tegra210_sor },
+       { .compatible = "nvidia,tegra124-sor", .data = &tegra124_sor },
+       { },
+};
+MODULE_DEVICE_TABLE(of, tegra_sor_of_match);
+
 static int tegra_sor_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *match;
        struct device_node *np;
        struct tegra_sor *sor;
        struct resource *regs;
        int err;
 
+       match = of_match_device(tegra_sor_of_match, &pdev->dev);
+
        sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL);
        if (!sor)
                return -ENOMEM;
 
        sor->output.dev = sor->dev = &pdev->dev;
+       sor->soc = match->data;
+
+       sor->settings = devm_kmemdup(&pdev->dev, sor->soc->settings,
+                                    sor->soc->num_settings *
+                                       sizeof(*sor->settings),
+                                    GFP_KERNEL);
+       if (!sor->settings)
+               return -ENOMEM;
+
+       sor->num_settings = sor->soc->num_settings;
 
        np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0);
        if (np) {
@@ -1599,51 +2406,106 @@ static int tegra_sor_probe(struct platform_device *pdev)
                        return -EPROBE_DEFER;
        }
 
+       if (!sor->dpaux) {
+               if (sor->soc->supports_hdmi) {
+                       sor->ops = &tegra_sor_hdmi_ops;
+               } else if (sor->soc->supports_lvds) {
+                       dev_err(&pdev->dev, "LVDS not supported yet\n");
+                       return -ENODEV;
+               } else {
+                       dev_err(&pdev->dev, "unknown (non-DP) support\n");
+                       return -ENODEV;
+               }
+       } else {
+               if (sor->soc->supports_edp) {
+                       sor->ops = &tegra_sor_edp_ops;
+               } else if (sor->soc->supports_dp) {
+                       dev_err(&pdev->dev, "DisplayPort not supported yet\n");
+                       return -ENODEV;
+               } else {
+                       dev_err(&pdev->dev, "unknown (DP) support\n");
+                       return -ENODEV;
+               }
+       }
+
        err = tegra_output_probe(&sor->output);
-       if (err < 0)
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to probe output: %d\n", err);
                return err;
+       }
+
+       if (sor->ops && sor->ops->probe) {
+               err = sor->ops->probe(sor);
+               if (err < 0) {
+                       dev_err(&pdev->dev, "failed to probe %s: %d\n",
+                               sor->ops->name, err);
+                       goto output;
+               }
+       }
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        sor->regs = devm_ioremap_resource(&pdev->dev, regs);
-       if (IS_ERR(sor->regs))
-               return PTR_ERR(sor->regs);
+       if (IS_ERR(sor->regs)) {
+               err = PTR_ERR(sor->regs);
+               goto remove;
+       }
 
        sor->rst = devm_reset_control_get(&pdev->dev, "sor");
-       if (IS_ERR(sor->rst))
-               return PTR_ERR(sor->rst);
+       if (IS_ERR(sor->rst)) {
+               err = PTR_ERR(sor->rst);
+               dev_err(&pdev->dev, "failed to get reset control: %d\n", err);
+               goto remove;
+       }
 
        sor->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(sor->clk))
-               return PTR_ERR(sor->clk);
+       if (IS_ERR(sor->clk)) {
+               err = PTR_ERR(sor->clk);
+               dev_err(&pdev->dev, "failed to get module clock: %d\n", err);
+               goto remove;
+       }
 
        sor->clk_parent = devm_clk_get(&pdev->dev, "parent");
-       if (IS_ERR(sor->clk_parent))
-               return PTR_ERR(sor->clk_parent);
+       if (IS_ERR(sor->clk_parent)) {
+               err = PTR_ERR(sor->clk_parent);
+               dev_err(&pdev->dev, "failed to get parent clock: %d\n", err);
+               goto remove;
+       }
 
        sor->clk_safe = devm_clk_get(&pdev->dev, "safe");
-       if (IS_ERR(sor->clk_safe))
-               return PTR_ERR(sor->clk_safe);
+       if (IS_ERR(sor->clk_safe)) {
+               err = PTR_ERR(sor->clk_safe);
+               dev_err(&pdev->dev, "failed to get safe clock: %d\n", err);
+               goto remove;
+       }
 
        sor->clk_dp = devm_clk_get(&pdev->dev, "dp");
-       if (IS_ERR(sor->clk_dp))
-               return PTR_ERR(sor->clk_dp);
+       if (IS_ERR(sor->clk_dp)) {
+               err = PTR_ERR(sor->clk_dp);
+               dev_err(&pdev->dev, "failed to get DP clock: %d\n", err);
+               goto remove;
+       }
 
        INIT_LIST_HEAD(&sor->client.list);
        sor->client.ops = &sor_client_ops;
        sor->client.dev = &pdev->dev;
 
-       mutex_init(&sor->lock);
-
        err = host1x_client_register(&sor->client);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to register host1x client: %d\n",
                        err);
-               return err;
+               goto remove;
        }
 
        platform_set_drvdata(pdev, sor);
 
        return 0;
+
+remove:
+       if (sor->ops && sor->ops->remove)
+               sor->ops->remove(sor);
+output:
+       tegra_output_remove(&sor->output);
+       return err;
 }
 
 static int tegra_sor_remove(struct platform_device *pdev)
@@ -1658,17 +2520,17 @@ static int tegra_sor_remove(struct platform_device *pdev)
                return err;
        }
 
+       if (sor->ops && sor->ops->remove) {
+               err = sor->ops->remove(sor);
+               if (err < 0)
+                       dev_err(&pdev->dev, "failed to remove SOR: %d\n", err);
+       }
+
        tegra_output_remove(&sor->output);
 
        return 0;
 }
 
-static const struct of_device_id tegra_sor_of_match[] = {
-       { .compatible = "nvidia,tegra124-sor", },
-       { },
-};
-MODULE_DEVICE_TABLE(of, tegra_sor_of_match);
-
 struct platform_driver tegra_sor_driver = {
        .driver = {
                .name = "tegra-sor",
index a5f8853fedb5aaf391e794c45ab49f754cb6df9a..2d31d027e3f68cfe22d36d03cd4f75f6a575333b 100644 (file)
@@ -11,9 +11,9 @@
 
 #define SOR_CTXSW 0x00
 
-#define SOR_SUPER_STATE_0 0x01
+#define SOR_SUPER_STATE0 0x01
 
-#define SOR_SUPER_STATE_1 0x02
+#define SOR_SUPER_STATE1 0x02
 #define  SOR_SUPER_STATE_ATTACHED              (1 << 3)
 #define  SOR_SUPER_STATE_MODE_NORMAL           (1 << 2)
 #define  SOR_SUPER_STATE_HEAD_MODE_MASK                (3 << 0)
@@ -21,9 +21,9 @@
 #define  SOR_SUPER_STATE_HEAD_MODE_SNOOZE      (1 << 0)
 #define  SOR_SUPER_STATE_HEAD_MODE_SLEEP       (0 << 0)
 
-#define SOR_STATE_0 0x03
+#define SOR_STATE0 0x03
 
-#define SOR_STATE_1 0x04
+#define SOR_STATE1 0x04
 #define  SOR_STATE_ASY_PIXELDEPTH_MASK         (0xf << 17)
 #define  SOR_STATE_ASY_PIXELDEPTH_BPP_18_444   (0x2 << 17)
 #define  SOR_STATE_ASY_PIXELDEPTH_BPP_24_444   (0x5 << 17)
 #define  SOR_STATE_ASY_PROTOCOL_CUSTOM         (0xf << 8)
 #define  SOR_STATE_ASY_PROTOCOL_DP_A           (0x8 << 8)
 #define  SOR_STATE_ASY_PROTOCOL_DP_B           (0x9 << 8)
+#define  SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A  (0x1 << 8)
 #define  SOR_STATE_ASY_PROTOCOL_LVDS           (0x0 << 8)
 #define  SOR_STATE_ASY_CRC_MODE_MASK           (0x3 << 6)
 #define  SOR_STATE_ASY_CRC_MODE_NON_ACTIVE     (0x2 << 6)
 #define  SOR_STATE_ASY_CRC_MODE_COMPLETE       (0x1 << 6)
 #define  SOR_STATE_ASY_CRC_MODE_ACTIVE         (0x0 << 6)
+#define  SOR_STATE_ASY_OWNER_MASK              0xf
 #define  SOR_STATE_ASY_OWNER(x)                        (((x) & 0xf) << 0)
 
-#define SOR_HEAD_STATE_0(x) (0x05 + (x))
-#define SOR_HEAD_STATE_1(x) (0x07 + (x))
-#define SOR_HEAD_STATE_2(x) (0x09 + (x))
-#define SOR_HEAD_STATE_3(x) (0x0b + (x))
-#define SOR_HEAD_STATE_4(x) (0x0d + (x))
-#define SOR_HEAD_STATE_5(x) (0x0f + (x))
+#define SOR_HEAD_STATE0(x) (0x05 + (x))
+#define  SOR_HEAD_STATE_RANGECOMPRESS_MASK (0x1 << 3)
+#define  SOR_HEAD_STATE_DYNRANGE_MASK (0x1 << 2)
+#define  SOR_HEAD_STATE_DYNRANGE_VESA (0 << 2)
+#define  SOR_HEAD_STATE_DYNRANGE_CEA (1 << 2)
+#define  SOR_HEAD_STATE_COLORSPACE_MASK (0x3 << 0)
+#define  SOR_HEAD_STATE_COLORSPACE_RGB (0 << 0)
+#define SOR_HEAD_STATE1(x) (0x07 + (x))
+#define SOR_HEAD_STATE2(x) (0x09 + (x))
+#define SOR_HEAD_STATE3(x) (0x0b + (x))
+#define SOR_HEAD_STATE4(x) (0x0d + (x))
+#define SOR_HEAD_STATE5(x) (0x0f + (x))
 #define SOR_CRC_CNTRL 0x11
 #define  SOR_CRC_CNTRL_ENABLE                  (1 << 0)
 #define SOR_DP_DEBUG_MVID 0x12
 #define  SOR_TEST_HEAD_MODE_MASK               (3 << 8)
 #define  SOR_TEST_HEAD_MODE_AWAKE              (2 << 8)
 
-#define SOR_PLL_0 0x17
-#define  SOR_PLL_0_ICHPMP_MASK                 (0xf << 24)
-#define  SOR_PLL_0_ICHPMP(x)                   (((x) & 0xf) << 24)
-#define  SOR_PLL_0_VCOCAP_MASK                 (0xf << 8)
-#define  SOR_PLL_0_VCOCAP(x)                   (((x) & 0xf) << 8)
-#define  SOR_PLL_0_VCOCAP_RST                  SOR_PLL_0_VCOCAP(3)
-#define  SOR_PLL_0_PLLREG_MASK                 (0x3 << 6)
-#define  SOR_PLL_0_PLLREG_LEVEL(x)             (((x) & 0x3) << 6)
-#define  SOR_PLL_0_PLLREG_LEVEL_V25            SOR_PLL_0_PLLREG_LEVEL(0)
-#define  SOR_PLL_0_PLLREG_LEVEL_V15            SOR_PLL_0_PLLREG_LEVEL(1)
-#define  SOR_PLL_0_PLLREG_LEVEL_V35            SOR_PLL_0_PLLREG_LEVEL(2)
-#define  SOR_PLL_0_PLLREG_LEVEL_V45            SOR_PLL_0_PLLREG_LEVEL(3)
-#define  SOR_PLL_0_PULLDOWN                    (1 << 5)
-#define  SOR_PLL_0_RESISTOR_EXT                        (1 << 4)
-#define  SOR_PLL_0_VCOPD                       (1 << 2)
-#define  SOR_PLL_0_POWER_OFF                   (1 << 0)
-
-#define SOR_PLL_1 0x18
+#define SOR_PLL0 0x17
+#define  SOR_PLL0_ICHPMP_MASK                  (0xf << 24)
+#define  SOR_PLL0_ICHPMP(x)                    (((x) & 0xf) << 24)
+#define  SOR_PLL0_VCOCAP_MASK                  (0xf << 8)
+#define  SOR_PLL0_VCOCAP(x)                    (((x) & 0xf) << 8)
+#define  SOR_PLL0_VCOCAP_RST                   SOR_PLL0_VCOCAP(3)
+#define  SOR_PLL0_PLLREG_MASK                  (0x3 << 6)
+#define  SOR_PLL0_PLLREG_LEVEL(x)              (((x) & 0x3) << 6)
+#define  SOR_PLL0_PLLREG_LEVEL_V25             SOR_PLL0_PLLREG_LEVEL(0)
+#define  SOR_PLL0_PLLREG_LEVEL_V15             SOR_PLL0_PLLREG_LEVEL(1)
+#define  SOR_PLL0_PLLREG_LEVEL_V35             SOR_PLL0_PLLREG_LEVEL(2)
+#define  SOR_PLL0_PLLREG_LEVEL_V45             SOR_PLL0_PLLREG_LEVEL(3)
+#define  SOR_PLL0_PULLDOWN                     (1 << 5)
+#define  SOR_PLL0_RESISTOR_EXT                 (1 << 4)
+#define  SOR_PLL0_VCOPD                                (1 << 2)
+#define  SOR_PLL0_PWR                          (1 << 0)
+
+#define SOR_PLL1 0x18
 /* XXX: read-only bit? */
-#define  SOR_PLL_1_TERM_COMPOUT                        (1 << 15)
-#define  SOR_PLL_1_TMDS_TERM                   (1 << 8)
-
-#define SOR_PLL_2 0x19
-#define  SOR_PLL_2_LVDS_ENABLE                 (1 << 25)
-#define  SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE                (1 << 24)
-#define  SOR_PLL_2_PORT_POWERDOWN              (1 << 23)
-#define  SOR_PLL_2_BANDGAP_POWERDOWN           (1 << 22)
-#define  SOR_PLL_2_POWERDOWN_OVERRIDE          (1 << 18)
-#define  SOR_PLL_2_SEQ_PLLCAPPD                        (1 << 17)
-
-#define SOR_PLL_3 0x1a
-#define  SOR_PLL_3_PLL_VDD_MODE_V1_8 (0 << 13)
-#define  SOR_PLL_3_PLL_VDD_MODE_V3_3 (1 << 13)
+#define  SOR_PLL1_LOADADJ_MASK                 (0xf << 20)
+#define  SOR_PLL1_LOADADJ(x)                   (((x) & 0xf) << 20)
+#define  SOR_PLL1_TERM_COMPOUT                 (1 << 15)
+#define  SOR_PLL1_TMDS_TERMADJ_MASK            (0xf << 9)
+#define  SOR_PLL1_TMDS_TERMADJ(x)              (((x) & 0xf) << 9)
+#define  SOR_PLL1_TMDS_TERM                    (1 << 8)
+
+#define SOR_PLL2 0x19
+#define  SOR_PLL2_LVDS_ENABLE                  (1 << 25)
+#define  SOR_PLL2_SEQ_PLLCAPPD_ENFORCE         (1 << 24)
+#define  SOR_PLL2_PORT_POWERDOWN               (1 << 23)
+#define  SOR_PLL2_BANDGAP_POWERDOWN            (1 << 22)
+#define  SOR_PLL2_POWERDOWN_OVERRIDE           (1 << 18)
+#define  SOR_PLL2_SEQ_PLLCAPPD                 (1 << 17)
+#define  SOR_PLL2_SEQ_PLL_PULLDOWN             (1 << 16)
+
+#define SOR_PLL3 0x1a
+#define  SOR_PLL3_BG_VREF_LEVEL_MASK           (0xf << 24)
+#define  SOR_PLL3_BG_VREF_LEVEL(x)             (((x) & 0xf) << 24)
+#define  SOR_PLL3_PLL_VDD_MODE_1V8             (0 << 13)
+#define  SOR_PLL3_PLL_VDD_MODE_3V3             (1 << 13)
 
 #define SOR_CSTM 0x1b
+#define  SOR_CSTM_ROTCLK_MASK                  (0xf << 24)
+#define  SOR_CSTM_ROTCLK(x)                    (((x) & 0xf) << 24)
 #define  SOR_CSTM_LVDS                         (1 << 16)
 #define  SOR_CSTM_LINK_ACT_B                   (1 << 15)
 #define  SOR_CSTM_LINK_ACT_A                   (1 << 14)
 #define  SOR_CSTM_UPPER                                (1 << 11)
 
 #define SOR_LVDS 0x1c
-#define SOR_CRC_A 0x1d
-#define  SOR_CRC_A_VALID                       (1 << 0)
-#define  SOR_CRC_A_RESET                       (1 << 0)
-#define SOR_CRC_B 0x1e
+#define SOR_CRCA 0x1d
+#define  SOR_CRCA_VALID                        (1 << 0)
+#define  SOR_CRCA_RESET                        (1 << 0)
+#define SOR_CRCB 0x1e
 #define SOR_BLANK 0x1f
 #define SOR_SEQ_CTL 0x20
+#define  SOR_SEQ_CTL_PD_PC_ALT(x)      (((x) & 0xf) << 12)
+#define  SOR_SEQ_CTL_PD_PC(x)          (((x) & 0xf) <<  8)
+#define  SOR_SEQ_CTL_PU_PC_ALT(x)      (((x) & 0xf) <<  4)
+#define  SOR_SEQ_CTL_PU_PC(x)          (((x) & 0xf) <<  0)
 
 #define SOR_LANE_SEQ_CTL 0x21
 #define  SOR_LANE_SEQ_CTL_TRIGGER              (1 << 31)
+#define  SOR_LANE_SEQ_CTL_STATE_BUSY           (1 << 28)
 #define  SOR_LANE_SEQ_CTL_SEQUENCE_UP          (0 << 20)
 #define  SOR_LANE_SEQ_CTL_SEQUENCE_DOWN                (1 << 20)
 #define  SOR_LANE_SEQ_CTL_POWER_STATE_UP       (0 << 16)
 #define  SOR_LANE_SEQ_CTL_POWER_STATE_DOWN     (1 << 16)
+#define  SOR_LANE_SEQ_CTL_DELAY(x)             (((x) & 0xf) << 12)
 
 #define SOR_SEQ_INST(x) (0x22 + (x))
+#define  SOR_SEQ_INST_PLL_PULLDOWN (1 << 31)
+#define  SOR_SEQ_INST_POWERDOWN_MACRO (1 << 30)
+#define  SOR_SEQ_INST_ASSERT_PLL_RESET (1 << 29)
+#define  SOR_SEQ_INST_BLANK_V (1 << 28)
+#define  SOR_SEQ_INST_BLANK_H (1 << 27)
+#define  SOR_SEQ_INST_BLANK_DE (1 << 26)
+#define  SOR_SEQ_INST_BLACK_DATA (1 << 25)
+#define  SOR_SEQ_INST_TRISTATE_IOS (1 << 24)
+#define  SOR_SEQ_INST_DRIVE_PWM_OUT_LO (1 << 23)
+#define  SOR_SEQ_INST_PIN_B_LOW (0 << 22)
+#define  SOR_SEQ_INST_PIN_B_HIGH (1 << 22)
+#define  SOR_SEQ_INST_PIN_A_LOW (0 << 21)
+#define  SOR_SEQ_INST_PIN_A_HIGH (1 << 21)
+#define  SOR_SEQ_INST_SEQUENCE_UP (0 << 19)
+#define  SOR_SEQ_INST_SEQUENCE_DOWN (1 << 19)
+#define  SOR_SEQ_INST_LANE_SEQ_STOP (0 << 18)
+#define  SOR_SEQ_INST_LANE_SEQ_RUN (1 << 18)
+#define  SOR_SEQ_INST_PORT_POWERDOWN (1 << 17)
+#define  SOR_SEQ_INST_PLL_POWERDOWN (1 << 16)
+#define  SOR_SEQ_INST_HALT (1 << 15)
+#define  SOR_SEQ_INST_WAIT_US (0 << 12)
+#define  SOR_SEQ_INST_WAIT_MS (1 << 12)
+#define  SOR_SEQ_INST_WAIT_VSYNC (2 << 12)
+#define  SOR_SEQ_INST_WAIT(x) (((x) & 0x3ff) << 0)
 
 #define SOR_PWM_DIV 0x32
 #define  SOR_PWM_DIV_MASK                      0xffffff
 #define  SOR_PWM_CTL_CLK_SEL                   (1 << 30)
 #define  SOR_PWM_CTL_DUTY_CYCLE_MASK           0xffffff
 
-#define SOR_VCRC_A_0 0x34
-#define SOR_VCRC_A_1 0x35
-#define SOR_VCRC_B_0 0x36
-#define SOR_VCRC_B_1 0x37
-#define SOR_CCRC_A_0 0x38
-#define SOR_CCRC_A_1 0x39
-#define SOR_CCRC_B_0 0x3a
-#define SOR_CCRC_B_1 0x3b
-#define SOR_EDATA_A_0 0x3c
-#define SOR_EDATA_A_1 0x3d
-#define SOR_EDATA_B_0 0x3e
-#define SOR_EDATA_B_1 0x3f
-#define SOR_COUNT_A_0 0x40
-#define SOR_COUNT_A_1 0x41
-#define SOR_COUNT_B_0 0x42
-#define SOR_COUNT_B_1 0x43
-#define SOR_DEBUG_A_0 0x44
-#define SOR_DEBUG_A_1 0x45
-#define SOR_DEBUG_B_0 0x46
-#define SOR_DEBUG_B_1 0x47
+#define SOR_VCRC_A0 0x34
+#define SOR_VCRC_A1 0x35
+#define SOR_VCRC_B0 0x36
+#define SOR_VCRC_B1 0x37
+#define SOR_CCRC_A0 0x38
+#define SOR_CCRC_A1 0x39
+#define SOR_CCRC_B0 0x3a
+#define SOR_CCRC_B1 0x3b
+#define SOR_EDATA_A0 0x3c
+#define SOR_EDATA_A1 0x3d
+#define SOR_EDATA_B0 0x3e
+#define SOR_EDATA_B1 0x3f
+#define SOR_COUNT_A0 0x40
+#define SOR_COUNT_A1 0x41
+#define SOR_COUNT_B0 0x42
+#define SOR_COUNT_B1 0x43
+#define SOR_DEBUG_A0 0x44
+#define SOR_DEBUG_A1 0x45
+#define SOR_DEBUG_B0 0x46
+#define SOR_DEBUG_B1 0x47
 #define SOR_TRIG 0x48
 #define SOR_MSCHECK 0x49
 #define SOR_XBAR_CTRL 0x4a
+#define  SOR_XBAR_CTRL_LINK1_XSEL(channel, value) ((((value) & 0x7) << ((channel) * 3)) << 17)
+#define  SOR_XBAR_CTRL_LINK0_XSEL(channel, value) ((((value) & 0x7) << ((channel) * 3)) <<  2)
+#define  SOR_XBAR_CTRL_LINK_SWAP (1 << 1)
+#define  SOR_XBAR_CTRL_BYPASS (1 << 0)
 #define SOR_XBAR_POL 0x4b
 
-#define SOR_DP_LINKCTL_0 0x4c
+#define SOR_DP_LINKCTL0 0x4c
 #define  SOR_DP_LINKCTL_LANE_COUNT_MASK                (0x1f << 16)
 #define  SOR_DP_LINKCTL_LANE_COUNT(x)          (((1 << (x)) - 1) << 16)
 #define  SOR_DP_LINKCTL_ENHANCED_FRAME         (1 << 14)
 #define  SOR_DP_LINKCTL_TU_SIZE(x)             (((x) & 0x7f) << 2)
 #define  SOR_DP_LINKCTL_ENABLE                 (1 << 0)
 
-#define SOR_DP_LINKCTL_1 0x4d
+#define SOR_DP_LINKCTL1 0x4d
 
-#define SOR_LANE_DRIVE_CURRENT_0 0x4e
-#define SOR_LANE_DRIVE_CURRENT_1 0x4f
-#define SOR_LANE4_DRIVE_CURRENT_0 0x50
-#define SOR_LANE4_DRIVE_CURRENT_1 0x51
+#define SOR_LANE_DRIVE_CURRENT0 0x4e
+#define SOR_LANE_DRIVE_CURRENT1 0x4f
+#define SOR_LANE4_DRIVE_CURRENT0 0x50
+#define SOR_LANE4_DRIVE_CURRENT1 0x51
 #define  SOR_LANE_DRIVE_CURRENT_LANE3(x) (((x) & 0xff) << 24)
 #define  SOR_LANE_DRIVE_CURRENT_LANE2(x) (((x) & 0xff) << 16)
 #define  SOR_LANE_DRIVE_CURRENT_LANE1(x) (((x) & 0xff) << 8)
 #define  SOR_LANE_DRIVE_CURRENT_LANE0(x) (((x) & 0xff) << 0)
 
-#define SOR_LANE_PREEMPHASIS_0 0x52
-#define SOR_LANE_PREEMPHASIS_1 0x53
-#define SOR_LANE4_PREEMPHASIS_0 0x54
-#define SOR_LANE4_PREEMPHASIS_1 0x55
+#define SOR_LANE_PREEMPHASIS0 0x52
+#define SOR_LANE_PREEMPHASIS1 0x53
+#define SOR_LANE4_PREEMPHASIS0 0x54
+#define SOR_LANE4_PREEMPHASIS1 0x55
 #define  SOR_LANE_PREEMPHASIS_LANE3(x) (((x) & 0xff) << 24)
 #define  SOR_LANE_PREEMPHASIS_LANE2(x) (((x) & 0xff) << 16)
 #define  SOR_LANE_PREEMPHASIS_LANE1(x) (((x) & 0xff) << 8)
 #define  SOR_LANE_PREEMPHASIS_LANE0(x) (((x) & 0xff) << 0)
 
-#define SOR_LANE_POST_CURSOR_0 0x56
-#define SOR_LANE_POST_CURSOR_1 0x57
-#define  SOR_LANE_POST_CURSOR_LANE3(x) (((x) & 0xff) << 24)
-#define  SOR_LANE_POST_CURSOR_LANE2(x) (((x) & 0xff) << 16)
-#define  SOR_LANE_POST_CURSOR_LANE1(x) (((x) & 0xff) << 8)
-#define  SOR_LANE_POST_CURSOR_LANE0(x) (((x) & 0xff) << 0)
+#define SOR_LANE_POSTCURSOR0 0x56
+#define SOR_LANE_POSTCURSOR1 0x57
+#define  SOR_LANE_POSTCURSOR_LANE3(x) (((x) & 0xff) << 24)
+#define  SOR_LANE_POSTCURSOR_LANE2(x) (((x) & 0xff) << 16)
+#define  SOR_LANE_POSTCURSOR_LANE1(x) (((x) & 0xff) << 8)
+#define  SOR_LANE_POSTCURSOR_LANE0(x) (((x) & 0xff) << 0)
 
-#define SOR_DP_CONFIG_0 0x58
+#define SOR_DP_CONFIG0 0x58
 #define SOR_DP_CONFIG_DISPARITY_NEGATIVE       (1 << 31)
 #define SOR_DP_CONFIG_ACTIVE_SYM_ENABLE                (1 << 26)
 #define SOR_DP_CONFIG_ACTIVE_SYM_POLARITY      (1 << 24)
 #define SOR_DP_CONFIG_WATERMARK_MASK   (0x3f << 0)
 #define SOR_DP_CONFIG_WATERMARK(x)     (((x) & 0x3f) << 0)
 
-#define SOR_DP_CONFIG_1 0x59
-#define SOR_DP_MN_0 0x5a
-#define SOR_DP_MN_1 0x5b
+#define SOR_DP_CONFIG1 0x59
+#define SOR_DP_MN0 0x5a
+#define SOR_DP_MN1 0x5b
 
-#define SOR_DP_PADCTL_0 0x5c
+#define SOR_DP_PADCTL0 0x5c
 #define  SOR_DP_PADCTL_PAD_CAL_PD      (1 << 23)
 #define  SOR_DP_PADCTL_TX_PU_ENABLE    (1 << 22)
 #define  SOR_DP_PADCTL_TX_PU_MASK      (0xff << 8)
 #define  SOR_DP_PADCTL_PD_TXD_1                (1 << 1)
 #define  SOR_DP_PADCTL_PD_TXD_2                (1 << 0)
 
-#define SOR_DP_PADCTL_1 0x5d
+#define SOR_DP_PADCTL1 0x5d
 
-#define SOR_DP_DEBUG_0 0x5e
-#define SOR_DP_DEBUG_1 0x5f
+#define SOR_DP_DEBUG0 0x5e
+#define SOR_DP_DEBUG1 0x5f
 
-#define SOR_DP_SPARE_0 0x60
-#define  SOR_DP_SPARE_MACRO_SOR_CLK    (1 << 2)
-#define  SOR_DP_SPARE_PANEL_INTERNAL   (1 << 1)
-#define  SOR_DP_SPARE_SEQ_ENABLE       (1 << 0)
+#define SOR_DP_SPARE0 0x60
+#define  SOR_DP_SPARE_DISP_VIDEO_PREAMBLE      (1 << 3)
+#define  SOR_DP_SPARE_MACRO_SOR_CLK            (1 << 2)
+#define  SOR_DP_SPARE_PANEL_INTERNAL           (1 << 1)
+#define  SOR_DP_SPARE_SEQ_ENABLE               (1 << 0)
 
-#define SOR_DP_SPARE_1 0x61
+#define SOR_DP_SPARE1 0x61
 #define SOR_DP_AUDIO_CTRL 0x62
 
 #define SOR_DP_AUDIO_HBLANK_SYMBOLS 0x63
 #define SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK (0x1fffff << 0)
 
 #define SOR_DP_GENERIC_INFOFRAME_HEADER 0x65
-#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_0 0x66
-#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_1 0x67
-#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_2 0x68
-#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_3 0x69
-#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_4 0x6a
-#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_5 0x6b
-#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_6 0x6c
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK0 0x66
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK1 0x67
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK2 0x68
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK3 0x69
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK4 0x6a
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK5 0x6b
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK6 0x6c
 
 #define SOR_DP_TPG 0x6d
 #define  SOR_DP_TPG_CHANNEL_CODING     (1 << 6)
 #define  SOR_DP_TPG_PATTERN_NONE       (0x0 << 0)
 
 #define SOR_DP_TPG_CONFIG 0x6e
-#define SOR_DP_LQ_CSTM_0 0x6f
-#define SOR_DP_LQ_CSTM_1 0x70
-#define SOR_DP_LQ_CSTM_2 0x71
+#define SOR_DP_LQ_CSTM0 0x6f
+#define SOR_DP_LQ_CSTM1 0x70
+#define SOR_DP_LQ_CSTM2 0x71
+
+#define SOR_HDMI_AUDIO_INFOFRAME_CTRL 0x9a
+#define SOR_HDMI_AUDIO_INFOFRAME_STATUS 0x9b
+#define SOR_HDMI_AUDIO_INFOFRAME_HEADER 0x9c
+
+#define SOR_HDMI_AVI_INFOFRAME_CTRL 0x9f
+#define  INFOFRAME_CTRL_CHECKSUM_ENABLE        (1 << 9)
+#define  INFOFRAME_CTRL_SINGLE         (1 << 8)
+#define  INFOFRAME_CTRL_OTHER          (1 << 4)
+#define  INFOFRAME_CTRL_ENABLE         (1 << 0)
+
+#define SOR_HDMI_AVI_INFOFRAME_STATUS 0xa0
+#define  INFOFRAME_STATUS_DONE         (1 << 0)
+
+#define SOR_HDMI_AVI_INFOFRAME_HEADER 0xa1
+#define  INFOFRAME_HEADER_LEN(x) (((x) & 0xff) << 16)
+#define  INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8)
+#define  INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0)
+
+#define SOR_HDMI_CTRL 0xc0
+#define  SOR_HDMI_CTRL_ENABLE (1 << 30)
+#define  SOR_HDMI_CTRL_MAX_AC_PACKET(x) (((x) & 0x1f) << 16)
+#define  SOR_HDMI_CTRL_AUDIO_LAYOUT (1 << 10)
+#define  SOR_HDMI_CTRL_REKEY(x) (((x) & 0x7f) << 0)
+
+#define SOR_REFCLK 0xe6
+#define  SOR_REFCLK_DIV_INT(x) ((((x) >> 2) & 0xff) << 8)
+#define  SOR_REFCLK_DIV_FRAC(x) (((x) & 0x3) << 6)
+
+#define SOR_INPUT_CONTROL 0xe8
+#define  SOR_INPUT_CONTROL_ARM_VIDEO_RANGE_LIMITED (1 << 1)
+#define  SOR_INPUT_CONTROL_HDMI_SRC_SELECT(x) (((x) & 0x1) << 0)
+
+#define SOR_HDMI_VSI_INFOFRAME_CTRL 0x123
+#define SOR_HDMI_VSI_INFOFRAME_STATUS 0x124
+#define SOR_HDMI_VSI_INFOFRAME_HEADER 0x125
 
 #endif
index 882cccdad27249c8e3afa992419fb0fb16bec97b..ac6fe40b99f753b267a5e78647c0bdb2e078c5bd 100644 (file)
@@ -490,7 +490,8 @@ pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp)
        else if (boot_cpu_data.x86 > 3)
                tmp = pgprot_noncached(tmp);
 #endif
-#if defined(__ia64__) || defined(__arm__) || defined(__powerpc__)
+#if defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \
+    defined(__powerpc__)
        if (caching_flags & TTM_PL_FLAG_WC)
                tmp = pgprot_writecombine(tmp);
        else
index bf080abc86d12c9bdcb8947d1d1d637d0b2a4bb7..4e19d0f9cc3094ae9585eef447c2439589a4a304 100644 (file)
@@ -340,7 +340,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage)
                swap_storage = shmem_file_setup("ttm swap",
                                                ttm->num_pages << PAGE_SHIFT,
                                                0);
-               if (unlikely(IS_ERR(swap_storage))) {
+               if (IS_ERR(swap_storage)) {
                        pr_err("Failed allocating swap storage\n");
                        return PTR_ERR(swap_storage);
                }
@@ -354,7 +354,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage)
                if (unlikely(from_page == NULL))
                        continue;
                to_page = shmem_read_mapping_page(swap_space, i);
-               if (unlikely(IS_ERR(to_page))) {
+               if (IS_ERR(to_page)) {
                        ret = PTR_ERR(to_page);
                        goto out_err;
                }
index 5fc16cecd3ba595584f01f5f9a7e0b729f125341..62c7b1dafaa4ba6f4c573fd6d631b86b3b83ce45 100644 (file)
@@ -288,7 +288,7 @@ static void udl_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect
 {
        struct udl_fbdev *ufbdev = info->par;
 
-       sys_fillrect(info, rect);
+       drm_fb_helper_sys_fillrect(info, rect);
 
        udl_handle_damage(&ufbdev->ufb, rect->dx, rect->dy, rect->width,
                          rect->height);
@@ -298,7 +298,7 @@ static void udl_fb_copyarea(struct fb_info *info, const struct fb_copyarea *regi
 {
        struct udl_fbdev *ufbdev = info->par;
 
-       sys_copyarea(info, region);
+       drm_fb_helper_sys_copyarea(info, region);
 
        udl_handle_damage(&ufbdev->ufb, region->dx, region->dy, region->width,
                          region->height);
@@ -308,7 +308,7 @@ static void udl_fb_imageblit(struct fb_info *info, const struct fb_image *image)
 {
        struct udl_fbdev *ufbdev = info->par;
 
-       sys_imageblit(info, image);
+       drm_fb_helper_sys_imageblit(info, image);
 
        udl_handle_damage(&ufbdev->ufb, image->dx, image->dy, image->width,
                          image->height);
@@ -476,7 +476,6 @@ static int udlfb_create(struct drm_fb_helper *helper,
                container_of(helper, struct udl_fbdev, helper);
        struct drm_device *dev = ufbdev->helper.dev;
        struct fb_info *info;
-       struct device *device = dev->dev;
        struct drm_framebuffer *fb;
        struct drm_mode_fb_cmd2 mode_cmd;
        struct udl_gem_object *obj;
@@ -506,21 +505,20 @@ static int udlfb_create(struct drm_fb_helper *helper,
                goto out_gfree;
        }
 
-       info = framebuffer_alloc(0, device);
-       if (!info) {
-               ret = -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info)) {
+               ret = PTR_ERR(info);
                goto out_gfree;
        }
        info->par = ufbdev;
 
        ret = udl_framebuffer_init(dev, &ufbdev->ufb, &mode_cmd, obj);
        if (ret)
-               goto out_gfree;
+               goto out_destroy_fbi;
 
        fb = &ufbdev->ufb.base;
 
        ufbdev->helper.fb = fb;
-       ufbdev->helper.fbdev = info;
 
        strcpy(info->fix.id, "udldrmfb");
 
@@ -533,18 +531,13 @@ static int udlfb_create(struct drm_fb_helper *helper,
        drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
        drm_fb_helper_fill_var(info, &ufbdev->helper, sizes->fb_width, sizes->fb_height);
 
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto out_gfree;
-       }
-
-
        DRM_DEBUG_KMS("allocated %dx%d vmal %p\n",
                      fb->width, fb->height,
                      ufbdev->ufb.obj->vmapping);
 
        return ret;
+out_destroy_fbi:
+       drm_fb_helper_release_fbi(helper);
 out_gfree:
        drm_gem_object_unreference(&ufbdev->ufb.obj->base);
 out:
@@ -558,14 +551,8 @@ static const struct drm_fb_helper_funcs udl_fb_helper_funcs = {
 static void udl_fbdev_destroy(struct drm_device *dev,
                              struct udl_fbdev *ufbdev)
 {
-       struct fb_info *info;
-       if (ufbdev->helper.fbdev) {
-               info = ufbdev->helper.fbdev;
-               unregister_framebuffer(info);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
+       drm_fb_helper_unregister_fbi(&ufbdev->helper);
+       drm_fb_helper_release_fbi(&ufbdev->helper);
        drm_fb_helper_fini(&ufbdev->helper);
        drm_framebuffer_unregister_private(&ufbdev->ufb.base);
        drm_framebuffer_cleanup(&ufbdev->ufb.base);
@@ -631,11 +618,7 @@ void udl_fbdev_unplug(struct drm_device *dev)
                return;
 
        ufbdev = udl->fbdev;
-       if (ufbdev->helper.fbdev) {
-               struct fb_info *info;
-               info = ufbdev->helper.fbdev;
-               unlink_framebuffer(info);
-       }
+       drm_fb_helper_unlink_fbi(&ufbdev->helper);
 }
 
 struct drm_framebuffer *
index df198d9e770c2f61882c9a1bdae771f8c9378f54..6a81e084593bde8539197f417cb72e56498ced22 100644 (file)
@@ -173,7 +173,7 @@ static void virtio_gpu_3d_fillrect(struct fb_info *info,
                                   const struct fb_fillrect *rect)
 {
        struct virtio_gpu_fbdev *vfbdev = info->par;
-       sys_fillrect(info, rect);
+       drm_fb_helper_sys_fillrect(info, rect);
        virtio_gpu_dirty_update(&vfbdev->vgfb, true, rect->dx, rect->dy,
                             rect->width, rect->height);
        schedule_delayed_work(&vfbdev->work, VIRTIO_GPU_FBCON_POLL_PERIOD);
@@ -183,7 +183,7 @@ static void virtio_gpu_3d_copyarea(struct fb_info *info,
                                   const struct fb_copyarea *area)
 {
        struct virtio_gpu_fbdev *vfbdev = info->par;
-       sys_copyarea(info, area);
+       drm_fb_helper_sys_copyarea(info, area);
        virtio_gpu_dirty_update(&vfbdev->vgfb, true, area->dx, area->dy,
                           area->width, area->height);
        schedule_delayed_work(&vfbdev->work, VIRTIO_GPU_FBCON_POLL_PERIOD);
@@ -193,7 +193,7 @@ static void virtio_gpu_3d_imageblit(struct fb_info *info,
                                    const struct fb_image *image)
 {
        struct virtio_gpu_fbdev *vfbdev = info->par;
-       sys_imageblit(info, image);
+       drm_fb_helper_sys_imageblit(info, image);
        virtio_gpu_dirty_update(&vfbdev->vgfb, true, image->dx, image->dy,
                             image->width, image->height);
        schedule_delayed_work(&vfbdev->work, VIRTIO_GPU_FBCON_POLL_PERIOD);
@@ -230,7 +230,6 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
        struct drm_framebuffer *fb;
        struct drm_mode_fb_cmd2 mode_cmd = {};
        struct virtio_gpu_object *obj;
-       struct device *device = vgdev->dev;
        uint32_t resid, format, size;
        int ret;
 
@@ -317,18 +316,12 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
        if (ret)
                goto err_obj_attach;
 
-       info = framebuffer_alloc(0, device);
-       if (!info) {
-               ret = -ENOMEM;
+       info = drm_fb_helper_alloc_fbi(helper);
+       if (IS_ERR(info)) {
+               ret = PTR_ERR(info);
                goto err_fb_alloc;
        }
 
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret) {
-               ret = -ENOMEM;
-               goto err_fb_alloc_cmap;
-       }
-
        info->par = helper;
 
        ret = virtio_gpu_framebuffer_init(dev, &vfbdev->vgfb,
@@ -339,7 +332,6 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
        fb = &vfbdev->vgfb.base;
 
        vfbdev->helper.fb = fb;
-       vfbdev->helper.fbdev = info;
 
        strcpy(info->fix.id, "virtiodrmfb");
        info->flags = FBINFO_DEFAULT;
@@ -357,9 +349,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
        return 0;
 
 err_fb_init:
-       fb_dealloc_cmap(&info->cmap);
-err_fb_alloc_cmap:
-       framebuffer_release(info);
+       drm_fb_helper_release_fbi(helper);
 err_fb_alloc:
        virtio_gpu_cmd_resource_inval_backing(vgdev, resid);
 err_obj_attach:
@@ -371,15 +361,11 @@ err_obj_vmap:
 static int virtio_gpu_fbdev_destroy(struct drm_device *dev,
                                    struct virtio_gpu_fbdev *vgfbdev)
 {
-       struct fb_info *info;
        struct virtio_gpu_framebuffer *vgfb = &vgfbdev->vgfb;
 
-       if (vgfbdev->helper.fbdev) {
-               info = vgfbdev->helper.fbdev;
+       drm_fb_helper_unregister_fbi(&vgfbdev->helper);
+       drm_fb_helper_release_fbi(&vgfbdev->helper);
 
-               unregister_framebuffer(info);
-               framebuffer_release(info);
-       }
        if (vgfb->obj)
                vgfb->obj = NULL;
        drm_fb_helper_fini(&vgfbdev->helper);
index 7ef77640028d7234ecc534a69540454ed12f6152..443d1ed00de7856a2998920e9e00ca6bf8a4902c 100644 (file)
@@ -190,7 +190,7 @@ static int vmw_gb_context_init(struct vmw_private *dev_priv,
 
        if (dev_priv->has_mob) {
                uctx->man = vmw_cmdbuf_res_man_create(dev_priv);
-               if (unlikely(IS_ERR(uctx->man))) {
+               if (IS_ERR(uctx->man)) {
                        ret = PTR_ERR(uctx->man);
                        uctx->man = NULL;
                        goto out_err;
index 5f849435ca4c2467363377b88acec869bee08e60..f97ec5686cbc155f39811e418f724317ce09b315 100644 (file)
@@ -1125,7 +1125,7 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
                return -EINVAL;
 
        vmaster = vmw_master_check(dev, file_priv, flags);
-       if (unlikely(IS_ERR(vmaster))) {
+       if (IS_ERR(vmaster)) {
                ret = PTR_ERR(vmaster);
 
                if (ret != -ERESTARTSYS)
index 5d72298918d92a28f6ca1fc0f848b0e4817b6dcf..61fb7f3de3119ae3f94ad6dd9fef57f0c9c780c4 100644 (file)
@@ -1354,8 +1354,9 @@ void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
        }
 }
 
-void vmw_du_connector_dpms(struct drm_connector *connector, int mode)
+int vmw_du_connector_dpms(struct drm_connector *connector, int mode)
 {
+       return 0;
 }
 
 void vmw_du_connector_save(struct drm_connector *connector)
index 876de908fce30db310551b65be6637addc440644..782df7ca97946220414dd66a2afbe4f94b6d403a 100644 (file)
@@ -196,7 +196,7 @@ void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
 int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
                           uint32_t handle, uint32_t width, uint32_t height);
 int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
-void vmw_du_connector_dpms(struct drm_connector *connector, int mode);
+int vmw_du_connector_dpms(struct drm_connector *connector, int mode);
 void vmw_du_connector_save(struct drm_connector *connector);
 void vmw_du_connector_restore(struct drm_connector *connector);
 enum drm_connector_status
index fbc6ee6ca3374276219c5a8ae5beab08f8149005..52a6fd224127ef113f2d23338a46d10df28e955e 100644 (file)
@@ -31,6 +31,9 @@
 #include "dev.h"
 
 #define MIPI_CAL_CTRL                  0x00
+#define MIPI_CAL_CTRL_NOISE_FILTER(x)  (((x) & 0xf) << 26)
+#define MIPI_CAL_CTRL_PRESCALE(x)      (((x) & 0x3) << 24)
+#define MIPI_CAL_CTRL_CLKEN_OVR                (1 << 4)
 #define MIPI_CAL_CTRL_START            (1 << 0)
 
 #define MIPI_CAL_AUTOCAL_CTRL          0x01
 #define MIPI_CAL_CONFIG_CSIC           0x07
 #define MIPI_CAL_CONFIG_CSID           0x08
 #define MIPI_CAL_CONFIG_CSIE           0x09
+#define MIPI_CAL_CONFIG_CSIF           0x0a
 #define MIPI_CAL_CONFIG_DSIA           0x0e
 #define MIPI_CAL_CONFIG_DSIB           0x0f
 #define MIPI_CAL_CONFIG_DSIC           0x10
 #define MIPI_CAL_CONFIG_DSID           0x11
 
-#define MIPI_CAL_CONFIG_DSIAB_CLK      0x19
-#define MIPI_CAL_CONFIG_DSICD_CLK      0x1a
+#define MIPI_CAL_CONFIG_DSIA_CLK       0x19
+#define MIPI_CAL_CONFIG_DSIB_CLK       0x1a
 #define MIPI_CAL_CONFIG_CSIAB_CLK      0x1b
+#define MIPI_CAL_CONFIG_DSIC_CLK       0x1c
 #define MIPI_CAL_CONFIG_CSICD_CLK      0x1c
+#define MIPI_CAL_CONFIG_DSID_CLK       0x1d
 #define MIPI_CAL_CONFIG_CSIE_CLK       0x1d
 
 /* for data and clock lanes */
 
 #define MIPI_CAL_BIAS_PAD_CFG1         0x17
 #define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16)
+#define MIPI_CAL_BIAS_PAD_DRV_UP_REF(x) (((x) & 0x7) << 8)
 
 #define MIPI_CAL_BIAS_PAD_CFG2         0x18
+#define MIPI_CAL_BIAS_PAD_VCLAMP(x)    (((x) & 0x7) << 16)
+#define MIPI_CAL_BIAS_PAD_VAUXP(x)     (((x) & 0x7) << 4)
 #define MIPI_CAL_BIAS_PAD_PDVREG       (1 << 1)
 
 struct tegra_mipi_pad {
@@ -86,13 +95,35 @@ struct tegra_mipi_soc {
        bool has_clk_lane;
        const struct tegra_mipi_pad *pads;
        unsigned int num_pads;
+
+       bool clock_enable_override;
+       bool needs_vclamp_ref;
+
+       /* bias pad configuration settings */
+       u8 pad_drive_down_ref;
+       u8 pad_drive_up_ref;
+
+       u8 pad_vclamp_level;
+       u8 pad_vauxp_level;
+
+       /* calibration settings for data lanes */
+       u8 hspdos;
+       u8 hspuos;
+       u8 termos;
+
+       /* calibration settings for clock lanes */
+       u8 hsclkpdos;
+       u8 hsclkpuos;
 };
 
 struct tegra_mipi {
        const struct tegra_mipi_soc *soc;
+       struct device *dev;
        void __iomem *regs;
        struct mutex lock;
        struct clk *clk;
+
+       unsigned long usage_count;
 };
 
 struct tegra_mipi_device {
@@ -114,6 +145,67 @@ static inline void tegra_mipi_writel(struct tegra_mipi *mipi, u32 value,
        writel(value, mipi->regs + (offset << 2));
 }
 
+static int tegra_mipi_power_up(struct tegra_mipi *mipi)
+{
+       u32 value;
+       int err;
+
+       err = clk_enable(mipi->clk);
+       if (err < 0)
+               return err;
+
+       value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG0);
+       value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
+
+       if (mipi->soc->needs_vclamp_ref)
+               value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
+
+       tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
+
+       value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2);
+       value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
+       tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
+
+       clk_disable(mipi->clk);
+
+       return 0;
+}
+
+static int tegra_mipi_power_down(struct tegra_mipi *mipi)
+{
+       u32 value;
+       int err;
+
+       err = clk_enable(mipi->clk);
+       if (err < 0)
+               return err;
+
+       /*
+        * The MIPI_CAL_BIAS_PAD_PDVREG controls a voltage regulator that
+        * supplies the DSI pads. This must be kept enabled until none of the
+        * DSI lanes are used anymore.
+        */
+       value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2);
+       value |= MIPI_CAL_BIAS_PAD_PDVREG;
+       tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
+
+       /*
+        * MIPI_CAL_BIAS_PAD_PDVCLAMP and MIPI_CAL_BIAS_PAD_E_VCLAMP_REF
+        * control a regulator that supplies current to the pre-driver logic.
+        * Powering down this regulator causes DSI to fail, so it must remain
+        * powered on until none of the DSI lanes are used anymore.
+        */
+       value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG0);
+
+       if (mipi->soc->needs_vclamp_ref)
+               value &= ~MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
+
+       value |= MIPI_CAL_BIAS_PAD_PDVCLAMP;
+       tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
+
+       return 0;
+}
+
 struct tegra_mipi_device *tegra_mipi_request(struct device *device)
 {
        struct device_node *np = device->of_node;
@@ -150,6 +242,20 @@ struct tegra_mipi_device *tegra_mipi_request(struct device *device)
        dev->pads = args.args[0];
        dev->device = device;
 
+       mutex_lock(&dev->mipi->lock);
+
+       if (dev->mipi->usage_count++ == 0) {
+               err = tegra_mipi_power_up(dev->mipi);
+               if (err < 0) {
+                       dev_err(dev->mipi->dev,
+                               "failed to power up MIPI bricks: %d\n",
+                               err);
+                       return ERR_PTR(err);
+               }
+       }
+
+       mutex_unlock(&dev->mipi->lock);
+
        return dev;
 
 put:
@@ -164,6 +270,25 @@ EXPORT_SYMBOL(tegra_mipi_request);
 
 void tegra_mipi_free(struct tegra_mipi_device *device)
 {
+       int err;
+
+       mutex_lock(&device->mipi->lock);
+
+       if (--device->mipi->usage_count == 0) {
+               err = tegra_mipi_power_down(device->mipi);
+               if (err < 0) {
+                       /*
+                        * Not much that can be done here, so an error message
+                        * will have to do.
+                        */
+                       dev_err(device->mipi->dev,
+                               "failed to power down MIPI bricks: %d\n",
+                               err);
+               }
+       }
+
+       mutex_unlock(&device->mipi->lock);
+
        platform_device_put(device->pdev);
        kfree(device);
 }
@@ -199,16 +324,15 @@ int tegra_mipi_calibrate(struct tegra_mipi_device *device)
 
        mutex_lock(&device->mipi->lock);
 
-       value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG0);
-       value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
-       value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
-       tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
-
-       tegra_mipi_writel(device->mipi, MIPI_CAL_BIAS_PAD_DRV_DN_REF(2),
-                         MIPI_CAL_BIAS_PAD_CFG1);
+       value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(soc->pad_drive_down_ref) |
+               MIPI_CAL_BIAS_PAD_DRV_UP_REF(soc->pad_drive_up_ref);
+       tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG1);
 
        value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
-       value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
+       value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7);
+       value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7);
+       value |= MIPI_CAL_BIAS_PAD_VCLAMP(soc->pad_vclamp_level);
+       value |= MIPI_CAL_BIAS_PAD_VAUXP(soc->pad_vauxp_level);
        tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
 
        for (i = 0; i < soc->num_pads; i++) {
@@ -216,20 +340,37 @@ int tegra_mipi_calibrate(struct tegra_mipi_device *device)
 
                if (device->pads & BIT(i)) {
                        data = MIPI_CAL_CONFIG_SELECT |
-                              MIPI_CAL_CONFIG_HSPDOS(0) |
-                              MIPI_CAL_CONFIG_HSPUOS(4) |
-                              MIPI_CAL_CONFIG_TERMOS(5);
+                              MIPI_CAL_CONFIG_HSPDOS(soc->hspdos) |
+                              MIPI_CAL_CONFIG_HSPUOS(soc->hspuos) |
+                              MIPI_CAL_CONFIG_TERMOS(soc->termos);
                        clk = MIPI_CAL_CONFIG_SELECT |
-                             MIPI_CAL_CONFIG_HSCLKPDOSD(0) |
-                             MIPI_CAL_CONFIG_HSCLKPUOSD(4);
+                             MIPI_CAL_CONFIG_HSCLKPDOSD(soc->hsclkpdos) |
+                             MIPI_CAL_CONFIG_HSCLKPUOSD(soc->hsclkpuos);
                }
 
                tegra_mipi_writel(device->mipi, data, soc->pads[i].data);
 
-               if (soc->has_clk_lane)
+               if (soc->has_clk_lane && soc->pads[i].clk != 0)
                        tegra_mipi_writel(device->mipi, clk, soc->pads[i].clk);
        }
 
+       value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
+       value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf);
+       value &= ~MIPI_CAL_CTRL_PRESCALE(0x3);
+       value |= MIPI_CAL_CTRL_NOISE_FILTER(0xa);
+       value |= MIPI_CAL_CTRL_PRESCALE(0x2);
+
+       if (!soc->clock_enable_override)
+               value &= ~MIPI_CAL_CTRL_CLKEN_OVR;
+       else
+               value |= MIPI_CAL_CTRL_CLKEN_OVR;
+
+       tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
+
+       /* clear any pending status bits */
+       value = tegra_mipi_readl(device->mipi, MIPI_CAL_STATUS);
+       tegra_mipi_writel(device->mipi, value, MIPI_CAL_STATUS);
+
        value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
        value |= MIPI_CAL_CTRL_START;
        tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
@@ -259,6 +400,17 @@ static const struct tegra_mipi_soc tegra114_mipi_soc = {
        .has_clk_lane = false,
        .pads = tegra114_mipi_pads,
        .num_pads = ARRAY_SIZE(tegra114_mipi_pads),
+       .clock_enable_override = true,
+       .needs_vclamp_ref = true,
+       .pad_drive_down_ref = 0x2,
+       .pad_drive_up_ref = 0x0,
+       .pad_vclamp_level = 0x0,
+       .pad_vauxp_level = 0x0,
+       .hspdos = 0x0,
+       .hspuos = 0x4,
+       .termos = 0x5,
+       .hsclkpdos = 0x0,
+       .hsclkpuos = 0x4,
 };
 
 static const struct tegra_mipi_pad tegra124_mipi_pads[] = {
@@ -266,20 +418,80 @@ static const struct tegra_mipi_pad tegra124_mipi_pads[] = {
        { .data = MIPI_CAL_CONFIG_CSIB, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
        { .data = MIPI_CAL_CONFIG_CSIC, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
        { .data = MIPI_CAL_CONFIG_CSID, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
-       { .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK },
-       { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIAB_CLK },
-       { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIAB_CLK },
+       { .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK  },
+       { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK  },
+       { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK  },
 };
 
 static const struct tegra_mipi_soc tegra124_mipi_soc = {
        .has_clk_lane = true,
        .pads = tegra124_mipi_pads,
        .num_pads = ARRAY_SIZE(tegra124_mipi_pads),
+       .clock_enable_override = true,
+       .needs_vclamp_ref = true,
+       .pad_drive_down_ref = 0x2,
+       .pad_drive_up_ref = 0x0,
+       .pad_vclamp_level = 0x0,
+       .pad_vauxp_level = 0x0,
+       .hspdos = 0x0,
+       .hspuos = 0x0,
+       .termos = 0x0,
+       .hsclkpdos = 0x1,
+       .hsclkpuos = 0x2,
+};
+
+static const struct tegra_mipi_soc tegra132_mipi_soc = {
+       .has_clk_lane = true,
+       .pads = tegra124_mipi_pads,
+       .num_pads = ARRAY_SIZE(tegra124_mipi_pads),
+       .clock_enable_override = false,
+       .needs_vclamp_ref = false,
+       .pad_drive_down_ref = 0x0,
+       .pad_drive_up_ref = 0x3,
+       .pad_vclamp_level = 0x0,
+       .pad_vauxp_level = 0x0,
+       .hspdos = 0x0,
+       .hspuos = 0x0,
+       .termos = 0x0,
+       .hsclkpdos = 0x3,
+       .hsclkpuos = 0x2,
+};
+
+static const struct tegra_mipi_pad tegra210_mipi_pads[] = {
+       { .data = MIPI_CAL_CONFIG_CSIA, .clk = 0 },
+       { .data = MIPI_CAL_CONFIG_CSIB, .clk = 0 },
+       { .data = MIPI_CAL_CONFIG_CSIC, .clk = 0 },
+       { .data = MIPI_CAL_CONFIG_CSID, .clk = 0 },
+       { .data = MIPI_CAL_CONFIG_CSIE, .clk = 0 },
+       { .data = MIPI_CAL_CONFIG_CSIF, .clk = 0 },
+       { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK },
+       { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK },
+       { .data = MIPI_CAL_CONFIG_DSIC, .clk = MIPI_CAL_CONFIG_DSIC_CLK },
+       { .data = MIPI_CAL_CONFIG_DSID, .clk = MIPI_CAL_CONFIG_DSID_CLK },
+};
+
+static const struct tegra_mipi_soc tegra210_mipi_soc = {
+       .has_clk_lane = true,
+       .pads = tegra210_mipi_pads,
+       .num_pads = ARRAY_SIZE(tegra210_mipi_pads),
+       .clock_enable_override = true,
+       .needs_vclamp_ref = false,
+       .pad_drive_down_ref = 0x0,
+       .pad_drive_up_ref = 0x3,
+       .pad_vclamp_level = 0x1,
+       .pad_vauxp_level = 0x1,
+       .hspdos = 0x0,
+       .hspuos = 0x2,
+       .termos = 0x0,
+       .hsclkpdos = 0x0,
+       .hsclkpuos = 0x2,
 };
 
-static struct of_device_id tegra_mipi_of_match[] = {
+static const struct of_device_id tegra_mipi_of_match[] = {
        { .compatible = "nvidia,tegra114-mipi", .data = &tegra114_mipi_soc },
        { .compatible = "nvidia,tegra124-mipi", .data = &tegra124_mipi_soc },
+       { .compatible = "nvidia,tegra132-mipi", .data = &tegra132_mipi_soc },
+       { .compatible = "nvidia,tegra210-mipi", .data = &tegra210_mipi_soc },
        { },
 };
 
@@ -299,6 +511,7 @@ static int tegra_mipi_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        mipi->soc = match->data;
+       mipi->dev = &pdev->dev;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mipi->regs = devm_ioremap_resource(&pdev->dev, res);
index 37ac7b5dbd066025c90009d6b44a1c08fffcc800..21060668fd25ba59b514c6a5a915a542ef8da159 100644 (file)
@@ -6,17 +6,19 @@
  * Licensed under GPLv2
  *
  * vga_switcheroo.c - Support for laptop with dual GPU using one set of outputs
-
- Switcher interface - methods require for ATPX and DCM
- - switchto - this throws the output MUX switch
- - discrete_set_power - sets the power state for the discrete card
-
- GPU driver interface
- - set_gpu_state - this should do the equiv of s/r for the card
-                 - this should *not* set the discrete power state
- - switch_check  - check if the device is in a position to switch now
+ *
Switcher interface - methods require for ATPX and DCM
- switchto - this throws the output MUX switch
- discrete_set_power - sets the power state for the discrete card
+ *
GPU driver interface
- set_gpu_state - this should do the equiv of s/r for the card
                - this should *not* set the discrete power state
- switch_check  - check if the device is in a position to switch now
  */
 
+#define pr_fmt(fmt) "vga_switcheroo: " fmt
+
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
@@ -111,7 +113,7 @@ int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
 
        vgasr_priv.handler = handler;
        if (vga_switcheroo_ready()) {
-               printk(KERN_INFO "vga_switcheroo: enabled\n");
+               pr_info("enabled\n");
                vga_switcheroo_enable();
        }
        mutex_unlock(&vgasr_mutex);
@@ -124,7 +126,7 @@ void vga_switcheroo_unregister_handler(void)
        mutex_lock(&vgasr_mutex);
        vgasr_priv.handler = NULL;
        if (vgasr_priv.active) {
-               pr_info("vga_switcheroo: disabled\n");
+               pr_info("disabled\n");
                vga_switcheroo_debugfs_fini(&vgasr_priv);
                vgasr_priv.active = false;
        }
@@ -155,7 +157,7 @@ static int register_client(struct pci_dev *pdev,
                vgasr_priv.registered_clients++;
 
        if (vga_switcheroo_ready()) {
-               printk(KERN_INFO "vga_switcheroo: enabled\n");
+               pr_info("enabled\n");
                vga_switcheroo_enable();
        }
        mutex_unlock(&vgasr_mutex);
@@ -167,7 +169,8 @@ int vga_switcheroo_register_client(struct pci_dev *pdev,
                                   bool driver_power_control)
 {
        return register_client(pdev, ops, -1,
-                              pdev == vga_default_device(), driver_power_control);
+                              pdev == vga_default_device(),
+                              driver_power_control);
 }
 EXPORT_SYMBOL(vga_switcheroo_register_client);
 
@@ -183,6 +186,7 @@ static struct vga_switcheroo_client *
 find_client_from_pci(struct list_head *head, struct pci_dev *pdev)
 {
        struct vga_switcheroo_client *client;
+
        list_for_each_entry(client, head, list)
                if (client->pdev == pdev)
                        return client;
@@ -193,6 +197,7 @@ static struct vga_switcheroo_client *
 find_client_from_id(struct list_head *head, int client_id)
 {
        struct vga_switcheroo_client *client;
+
        list_for_each_entry(client, head, list)
                if (client->id == client_id)
                        return client;
@@ -203,6 +208,7 @@ static struct vga_switcheroo_client *
 find_active_client(struct list_head *head)
 {
        struct vga_switcheroo_client *client;
+
        list_for_each_entry(client, head, list)
                if (client->active && client_is_vga(client))
                        return client;
@@ -235,7 +241,7 @@ void vga_switcheroo_unregister_client(struct pci_dev *pdev)
                kfree(client);
        }
        if (vgasr_priv.active && vgasr_priv.registered_clients < 2) {
-               printk(KERN_INFO "vga_switcheroo: disabled\n");
+               pr_info("disabled\n");
                vga_switcheroo_debugfs_fini(&vgasr_priv);
                vgasr_priv.active = false;
        }
@@ -260,10 +266,12 @@ static int vga_switcheroo_show(struct seq_file *m, void *v)
 {
        struct vga_switcheroo_client *client;
        int i = 0;
+
        mutex_lock(&vgasr_mutex);
        list_for_each_entry(client, &vgasr_priv.clients, list) {
                seq_printf(m, "%d:%s%s:%c:%s%s:%s\n", i,
-                          client_id(client) == VGA_SWITCHEROO_DIS ? "DIS" : "IGD",
+                          client_id(client) == VGA_SWITCHEROO_DIS ? "DIS" :
+                                                                    "IGD",
                           client_is_vga(client) ? "" : "-Audio",
                           client->active ? '+' : ' ',
                           client->driver_power_control ? "Dyn" : "",
@@ -347,6 +355,7 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
 
        if (new_client->fb_info) {
                struct fb_event event;
+
                console_lock();
                event.info = new_client->fb_info;
                fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event);
@@ -375,7 +384,7 @@ static bool check_can_switch(void)
 
        list_for_each_entry(client, &vgasr_priv.clients, list) {
                if (!client->ops->can_switch(client->pdev)) {
-                       printk(KERN_ERR "vga_switcheroo: client %x refused switch\n", client->id);
+                       pr_err("client %x refused switch\n", client->id);
                        return false;
                }
        }
@@ -484,20 +493,20 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
        if (can_switch) {
                ret = vga_switchto_stage1(client);
                if (ret)
-                       printk(KERN_ERR "vga_switcheroo: switching failed stage 1 %d\n", ret);
+                       pr_err("switching failed stage 1 %d\n", ret);
 
                ret = vga_switchto_stage2(client);
                if (ret)
-                       printk(KERN_ERR "vga_switcheroo: switching failed stage 2 %d\n", ret);
+                       pr_err("switching failed stage 2 %d\n", ret);
 
        } else {
-               printk(KERN_INFO "vga_switcheroo: setting delayed switch to client %d\n", client->id);
+               pr_info("setting delayed switch to client %d\n", client->id);
                vgasr_priv.delayed_switch_active = true;
                vgasr_priv.delayed_client_id = client_id;
 
                ret = vga_switchto_stage1(client);
                if (ret)
-                       printk(KERN_ERR "vga_switcheroo: delayed switching stage 1 failed %d\n", ret);
+                       pr_err("delayed switching stage 1 failed %d\n", ret);
        }
 
 out:
@@ -516,32 +525,32 @@ static const struct file_operations vga_switcheroo_debugfs_fops = {
 
 static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv)
 {
-       if (priv->switch_file) {
-               debugfs_remove(priv->switch_file);
-               priv->switch_file = NULL;
-       }
-       if (priv->debugfs_root) {
-               debugfs_remove(priv->debugfs_root);
-               priv->debugfs_root = NULL;
-       }
+       debugfs_remove(priv->switch_file);
+       priv->switch_file = NULL;
+
+       debugfs_remove(priv->debugfs_root);
+       priv->debugfs_root = NULL;
 }
 
 static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv)
 {
+       static const char mp[] = "/sys/kernel/debug";
+
        /* already initialised */
        if (priv->debugfs_root)
                return 0;
        priv->debugfs_root = debugfs_create_dir("vgaswitcheroo", NULL);
 
        if (!priv->debugfs_root) {
-               printk(KERN_ERR "vga_switcheroo: Cannot create /sys/kernel/debug/vgaswitcheroo\n");
+               pr_err("Cannot create %s/vgaswitcheroo\n", mp);
                goto fail;
        }
 
        priv->switch_file = debugfs_create_file("switch", 0644,
-                                               priv->debugfs_root, NULL, &vga_switcheroo_debugfs_fops);
+                                               priv->debugfs_root, NULL,
+                                               &vga_switcheroo_debugfs_fops);
        if (!priv->switch_file) {
-               printk(KERN_ERR "vga_switcheroo: cannot create /sys/kernel/debug/vgaswitcheroo/switch\n");
+               pr_err("cannot create %s/vgaswitcheroo/switch\n", mp);
                goto fail;
        }
        return 0;
@@ -560,7 +569,8 @@ int vga_switcheroo_process_delayed_switch(void)
        if (!vgasr_priv.delayed_switch_active)
                goto err;
 
-       printk(KERN_INFO "vga_switcheroo: processing delayed switch to %d\n", vgasr_priv.delayed_client_id);
+       pr_info("processing delayed switch to %d\n",
+               vgasr_priv.delayed_client_id);
 
        client = find_client_from_id(&vgasr_priv.clients,
                                     vgasr_priv.delayed_client_id);
@@ -569,7 +579,7 @@ int vga_switcheroo_process_delayed_switch(void)
 
        ret = vga_switchto_stage2(client);
        if (ret)
-               printk(KERN_ERR "vga_switcheroo: delayed switching failed stage 2 %d\n", ret);
+               pr_err("delayed switching failed stage 2 %d\n", ret);
 
        vgasr_priv.delayed_switch_active = false;
        err = 0;
@@ -579,7 +589,8 @@ err:
 }
 EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
 
-static void vga_switcheroo_power_switch(struct pci_dev *pdev, enum vga_switcheroo_state state)
+static void vga_switcheroo_power_switch(struct pci_dev *pdev,
+                                       enum vga_switcheroo_state state)
 {
        struct vga_switcheroo_client *client;
 
@@ -598,7 +609,8 @@ static void vga_switcheroo_power_switch(struct pci_dev *pdev, enum vga_switchero
 
 /* force a PCI device to a certain state - mainly to turn off audio clients */
 
-void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic)
+void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev,
+                                      enum vga_switcheroo_state dynamic)
 {
        struct vga_switcheroo_client *client;
 
@@ -644,7 +656,8 @@ static int vga_switcheroo_runtime_resume(struct device *dev)
 
 /* this version is for the case where the power switch is separate
    to the device being powered down. */
-int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain)
+int vga_switcheroo_init_domain_pm_ops(struct device *dev,
+                                     struct dev_pm_domain *domain)
 {
        /* copy over all the bus versions */
        if (dev->bus && dev->bus->pm) {
@@ -675,7 +688,8 @@ static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev)
        /* we need to check if we have to switch back on the video
           device so the audio device can come back */
        list_for_each_entry(client, &vgasr_priv.clients, list) {
-               if (PCI_SLOT(client->pdev->devfn) == PCI_SLOT(pdev->devfn) && client_is_vga(client)) {
+               if (PCI_SLOT(client->pdev->devfn) == PCI_SLOT(pdev->devfn) &&
+                   client_is_vga(client)) {
                        found = client;
                        ret = pm_runtime_get_sync(&client->pdev->dev);
                        if (ret) {
@@ -695,12 +709,15 @@ static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev)
        return ret;
 }
 
-int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain)
+int
+vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev,
+                                                struct dev_pm_domain *domain)
 {
        /* copy over all the bus versions */
        if (dev->bus && dev->bus->pm) {
                domain->ops = *dev->bus->pm;
-               domain->ops.runtime_resume = vga_switcheroo_runtime_resume_hdmi_audio;
+               domain->ops.runtime_resume =
+                       vga_switcheroo_runtime_resume_hdmi_audio;
 
                dev->pm_domain = domain;
                return 0;
index 7bcbf863656ec6f2c1e76d6156365fc0548230ff..a0b4334561078bbd0a2d10a1a2816a372c26f33b 100644 (file)
@@ -29,6 +29,8 @@
  *
  */
 
+#define pr_fmt(fmt) "vgaarb: " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -134,7 +136,6 @@ struct pci_dev *vga_default_device(void)
 {
        return vga_default;
 }
-
 EXPORT_SYMBOL_GPL(vga_default_device);
 
 void vga_set_default_device(struct pci_dev *pdev)
@@ -298,9 +299,9 @@ enable_them:
 
        pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
 
-       if (!vgadev->bridge_has_one_vga) {
+       if (!vgadev->bridge_has_one_vga)
                vga_irq_set_state(vgadev, true);
-       }
+
        vgadev->owns |= wants;
 lock_them:
        vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK);
@@ -452,15 +453,15 @@ bail:
 }
 EXPORT_SYMBOL(vga_put);
 
-/* Rules for using a bridge to control a VGA descendant decoding:
-   if a bridge has only one VGA descendant then it can be used
-   to control the VGA routing for that device.
-   It should always use the bridge closest to the device to control it.
-   If a bridge has a direct VGA descendant, but also have a sub-bridge
-   VGA descendant then we cannot use that bridge to control the direct VGA descendant.
-   So for every device we register, we need to iterate all its parent bridges
  so we can invalidate any devices using them properly.
-*/
+/*
+ * Rules for using a bridge to control a VGA descendant decoding: if a bridge
+ * has only one VGA descendant then it can be used to control the VGA routing
+ * for that device. It should always use the bridge closest to the device to
+ * control it. If a bridge has a direct VGA descendant, but also have a sub-
+ * bridge VGA descendant then we cannot use that bridge to control the direct
+ * VGA descendant. So for every device we register, we need to iterate all
* its parent bridges so we can invalidate any devices using them properly.
+ */
 static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev)
 {
        struct vga_device *same_bridge_vgadev;
@@ -484,21 +485,26 @@ static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev)
 
                        /* see if the share a bridge with this device */
                        if (new_bridge == bridge) {
-                               /* if their direct parent bridge is the same
-                                  as any bridge of this device then it can't be used
-                                  for that device */
+                               /*
+                                * If their direct parent bridge is the same
+                                * as any bridge of this device then it can't
+                                * be used for that device.
+                                */
                                same_bridge_vgadev->bridge_has_one_vga = false;
                        }
 
-                       /* now iterate the previous devices bridge hierarchy */
-                       /* if the new devices parent bridge is in the other devices
-                          hierarchy then we can't use it to control this device */
+                       /*
+                        * Now iterate the previous devices bridge hierarchy.
+                        * If the new devices parent bridge is in the other
+                        * devices hierarchy then we can't use it to control
+                        * this device
+                        */
                        while (bus) {
                                bridge = bus->self;
-                               if (bridge) {
-                                       if (bridge == vgadev->pdev->bus->self)
-                                               vgadev->bridge_has_one_vga = false;
-                               }
+
+                               if (bridge && bridge == vgadev->pdev->bus->self)
+                                       vgadev->bridge_has_one_vga = false;
+
                                bus = bus->parent;
                        }
                }
@@ -527,10 +533,10 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
        /* Allocate structure */
        vgadev = kmalloc(sizeof(struct vga_device), GFP_KERNEL);
        if (vgadev == NULL) {
-               pr_err("vgaarb: failed to allocate pci device\n");
-               /* What to do on allocation failure ? For now, let's
-                * just do nothing, I'm not sure there is anything saner
-                * to be done
+               pr_err("failed to allocate pci device\n");
+               /*
+                * What to do on allocation failure ? For now, let's just do
+                * nothing, I'm not sure there is anything saner to be done.
                 */
                return false;
        }
@@ -566,8 +572,8 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
                bridge = bus->self;
                if (bridge) {
                        u16 l;
-                       pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
-                                            &l);
+
+                       pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &l);
                        if (!(l & PCI_BRIDGE_CTL_VGA)) {
                                vgadev->owns = 0;
                                break;
@@ -581,8 +587,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
         */
        if (vga_default == NULL &&
            ((vgadev->owns & VGA_RSRC_LEGACY_MASK) == VGA_RSRC_LEGACY_MASK)) {
-               pr_info("vgaarb: setting as boot device: PCI:%s\n",
-                       pci_name(pdev));
+               pr_info("setting as boot device: PCI:%s\n", pci_name(pdev));
                vga_set_default_device(pdev);
        }
 
@@ -591,7 +596,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
        /* Add to the list */
        list_add(&vgadev->list, &vga_list);
        vga_count++;
-       pr_info("vgaarb: device added: PCI:%s,decodes=%s,owns=%s,locks=%s\n",
+       pr_info("device added: PCI:%s,decodes=%s,owns=%s,locks=%s\n",
                pci_name(pdev),
                vga_iostate_to_str(vgadev->decodes),
                vga_iostate_to_str(vgadev->owns),
@@ -651,7 +656,7 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev,
        decodes_unlocked = vgadev->locks & decodes_removed;
        vgadev->decodes = new_decodes;
 
-       pr_info("vgaarb: device changed decodes: PCI:%s,olddecodes=%s,decodes=%s:owns=%s\n",
+       pr_info("device changed decodes: PCI:%s,olddecodes=%s,decodes=%s:owns=%s\n",
                pci_name(vgadev->pdev),
                vga_iostate_to_str(old_decodes),
                vga_iostate_to_str(vgadev->decodes),
@@ -673,10 +678,12 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev,
        if (!(old_decodes & VGA_RSRC_LEGACY_MASK) &&
            new_decodes & VGA_RSRC_LEGACY_MASK)
                vga_decode_count++;
-       pr_debug("vgaarb: decoding count now is: %d\n", vga_decode_count);
+       pr_debug("decoding count now is: %d\n", vga_decode_count);
 }
 
-static void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace)
+static void __vga_set_legacy_decoding(struct pci_dev *pdev,
+                                     unsigned int decodes,
+                                     bool userspace)
 {
        struct vga_device *vgadev;
        unsigned long flags;
@@ -712,7 +719,8 @@ EXPORT_SYMBOL(vga_set_legacy_decoding);
 /* call with NULL to unregister */
 int vga_client_register(struct pci_dev *pdev, void *cookie,
                        void (*irq_set_state)(void *cookie, bool state),
-                       unsigned int (*set_vga_decode)(void *cookie, bool decode))
+                       unsigned int (*set_vga_decode)(void *cookie,
+                                                      bool decode))
 {
        int ret = -ENODEV;
        struct vga_device *vgadev;
@@ -832,7 +840,7 @@ static int vga_pci_str_to_vars(char *buf, int count, unsigned int *domain,
        return 1;
 }
 
-static ssize_t vga_arb_read(struct file *file, char __user * buf,
+static ssize_t vga_arb_read(struct file *file, char __user *buf,
                            size_t count, loff_t *ppos)
 {
        struct vga_arb_private *priv = file->private_data;
@@ -899,7 +907,7 @@ done:
  * TODO: To avoid parsing inside kernel and to improve the speed we may
  * consider use ioctl here
  */
-static ssize_t vga_arb_write(struct file *file, const char __user * buf,
+static ssize_t vga_arb_write(struct file *file, const char __user *buf,
                             size_t count, loff_t *ppos)
 {
        struct vga_arb_private *priv = file->private_data;
@@ -1075,13 +1083,13 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
                                ret_val = -EPROTO;
                                goto done;
                        }
-                       pr_debug("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos,
+                       pr_debug("%s ==> %x:%x:%x.%x\n", curr_pos,
                                domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
 
                        pdev = pci_get_domain_bus_and_slot(domain, bus, devfn);
-                       pr_debug("vgaarb: pdev %p\n", pdev);
+                       pr_debug("pdev %p\n", pdev);
                        if (!pdev) {
-                               pr_err("vgaarb: invalid PCI address %x:%x:%x\n",
+                               pr_err("invalid PCI address %x:%x:%x\n",
                                        domain, bus, devfn);
                                ret_val = -ENODEV;
                                goto done;
@@ -1089,10 +1097,13 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
                }
 
                vgadev = vgadev_find(pdev);
-               pr_debug("vgaarb: vgadev %p\n", vgadev);
+               pr_debug("vgadev %p\n", vgadev);
                if (vgadev == NULL) {
-                       pr_err("vgaarb: this pci device is not a vga device\n");
-                       pci_dev_put(pdev);
+                       if (pdev) {
+                               pr_err("this pci device is not a vga device\n");
+                               pci_dev_put(pdev);
+                       }
+
                        ret_val = -ENODEV;
                        goto done;
                }
@@ -1109,7 +1120,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
                        }
                }
                if (i == MAX_USER_CARDS) {
-                       pr_err("vgaarb: maximum user cards (%d) number reached!\n",
+                       pr_err("maximum user cards (%d) number reached!\n",
                                MAX_USER_CARDS);
                        pci_dev_put(pdev);
                        /* XXX: which value to return? */
@@ -1125,7 +1136,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
        } else if (strncmp(curr_pos, "decodes ", 8) == 0) {
                curr_pos += 8;
                remaining -= 8;
-               pr_debug("vgaarb: client 0x%p called 'decodes'\n", priv);
+               pr_debug("client 0x%p called 'decodes'\n", priv);
 
                if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) {
                        ret_val = -EPROTO;
@@ -1150,7 +1161,7 @@ done:
        return ret_val;
 }
 
-static unsigned int vga_arb_fpoll(struct file *file, poll_table * wait)
+static unsigned int vga_arb_fpoll(struct file *file, poll_table *wait)
 {
        struct vga_arb_private *priv = file->private_data;
 
@@ -1246,7 +1257,8 @@ static void vga_arbiter_notify_clients(void)
                else
                        new_state = true;
                if (vgadev->set_vga_decode) {
-                       new_decodes = vgadev->set_vga_decode(vgadev->cookie, new_state);
+                       new_decodes = vgadev->set_vga_decode(vgadev->cookie,
+                                                            new_state);
                        vga_update_device_decodes(vgadev, new_decodes);
                }
        }
@@ -1300,7 +1312,7 @@ static int __init vga_arb_device_init(void)
 
        rc = misc_register(&vga_arb_device);
        if (rc < 0)
-               pr_err("vgaarb: error %d registering device\n", rc);
+               pr_err("error %d registering device\n", rc);
 
        bus_register_notifier(&pci_bus_type, &pci_notifier);
 
@@ -1312,21 +1324,29 @@ static int __init vga_arb_device_init(void)
                               PCI_ANY_ID, pdev)) != NULL)
                vga_arbiter_add_pci_device(pdev);
 
-       pr_info("vgaarb: loaded\n");
+       pr_info("loaded\n");
 
        list_for_each_entry(vgadev, &vga_list, list) {
 #if defined(CONFIG_X86) || defined(CONFIG_IA64)
-               /* Override I/O based detection done by vga_arbiter_add_pci_device()
-                * as it may take the wrong device (e.g. on Apple system under EFI).
+               /*
+                * Override vga_arbiter_add_pci_device()'s I/O based detection
+                * as it may take the wrong device (e.g. on Apple system under
+                * EFI).
                 *
-                * Select the device owning the boot framebuffer if there is one.
+                * Select the device owning the boot framebuffer if there is
+                * one.
                 */
-               resource_size_t start, end;
+               resource_size_t start, end, limit;
+               unsigned long flags;
                int i;
 
+               limit = screen_info.lfb_base + screen_info.lfb_size;
+
                /* Does firmware framebuffer belong to us? */
                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-                       if (!(pci_resource_flags(vgadev->pdev, i) & IORESOURCE_MEM))
+                       flags = pci_resource_flags(vgadev->pdev, i);
+
+                       if ((flags & IORESOURCE_MEM) == 0)
                                continue;
 
                        start = pci_resource_start(vgadev->pdev, i);
@@ -1335,22 +1355,24 @@ static int __init vga_arb_device_init(void)
                        if (!start || !end)
                                continue;
 
-                       if (screen_info.lfb_base < start ||
-                           (screen_info.lfb_base + screen_info.lfb_size) >= end)
+                       if (screen_info.lfb_base < start || limit >= end)
                                continue;
+
                        if (!vga_default_device())
-                               pr_info("vgaarb: setting as boot device: PCI:%s\n",
+                               pr_info("setting as boot device: PCI:%s\n",
                                        pci_name(vgadev->pdev));
                        else if (vgadev->pdev != vga_default_device())
-                               pr_info("vgaarb: overriding boot device: PCI:%s\n",
+                               pr_info("overriding boot device: PCI:%s\n",
                                        pci_name(vgadev->pdev));
                        vga_set_default_device(vgadev->pdev);
                }
 #endif
                if (vgadev->bridge_has_one_vga)
-                       pr_info("vgaarb: bridge control possible %s\n", pci_name(vgadev->pdev));
+                       pr_info("bridge control possible %s\n",
+                               pci_name(vgadev->pdev));
                else
-                       pr_info("vgaarb: no bridge control possible %s\n", pci_name(vgadev->pdev));
+                       pr_info("no bridge control possible %s\n",
+                               pci_name(vgadev->pdev));
        }
        return rc;
 }
index f822fd2a1adabc4b3e53d86155c2d9e50d3d241e..884d82f9190e214636a539cb2db884a1d175c945 100644 (file)
@@ -546,6 +546,12 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
index 157c627750535e8943769e3078de068e4f1c7a47..e6fce23b121adb662656bea26d8a4ace812afc9c 100644 (file)
@@ -1782,6 +1782,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -2463,6 +2466,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { }
index 3318de690e00666bf7da60c84189a1fc54a0a544..a2dbbbe0d8d7e81b06ac6d646737413fe4d1d357 100644 (file)
@@ -356,6 +356,8 @@ static int cp2112_read(struct cp2112_device *dev, u8 *data, size_t size)
        struct cp2112_force_read_report report;
        int ret;
 
+       if (size > sizeof(dev->read_data))
+               size = sizeof(dev->read_data);
        report.report = CP2112_DATA_READ_FORCE_SEND;
        report.length = cpu_to_be16(size);
 
index b04b0820d816323a01d147c702503b0797734ea4..b3b225b75d0ab7e497c389d0c9caa777da1f6948 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI   0x0290
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO    0x0291
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS    0x0292
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI   0x0272
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO            0x0273
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS            0x0274
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
 #define USB_DEVICE_ID_APPLE_IRCONTROL  0x8240
index 3511bbaba505a4524ad382297ec1e486e21e7e48..e3c63640df737d5527c6d2609622417a4e03c8d3 100644 (file)
@@ -462,12 +462,15 @@ out:
 
 static void hidinput_cleanup_battery(struct hid_device *dev)
 {
+       const struct power_supply_desc *psy_desc;
+
        if (!dev->battery)
                return;
 
+       psy_desc = dev->battery->desc;
        power_supply_unregister(dev->battery);
-       kfree(dev->battery->desc->name);
-       kfree(dev->battery->desc);
+       kfree(psy_desc->name);
+       kfree(psy_desc);
        dev->battery = NULL;
 }
 #else  /* !CONFIG_HID_BATTERY_STRENGTH */
index 6a9b05b328a9d40e06b09ed8f8c6e6010669374b..7c811252c1cefebb2418944a7f391117a8a92b6d 100644 (file)
@@ -778,9 +778,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        /*
         * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
         * for the stylus.
+        * The check for mt_report_id ensures we don't process
+        * HID_DG_CONTACTCOUNT from the pen report as it is outside the physical
+        * collection, but within the report ID.
         */
        if (field->physical == HID_DG_STYLUS)
                return 0;
+       else if ((field->physical == 0) &&
+                (field->report->id != td->mt_report_id) &&
+                (td->mt_report_id != -1))
+               return 0;
 
        if (field->application == HID_DG_TOUCHSCREEN ||
            field->application == HID_DG_TOUCHPAD)
index 94167310e15a4c95001d339d4da3b7319f9005eb..b905d501e752d607b6fc1731ad89ff3d23ce7cd0 100644 (file)
@@ -858,7 +858,7 @@ static int uclogic_tablet_enable(struct hid_device *hdev)
        for (p = drvdata->rdesc;
             p <= drvdata->rdesc + drvdata->rsize - 4;) {
                if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
-                   p[3] < sizeof(params)) {
+                   p[3] < ARRAY_SIZE(params)) {
                        v = params[p[3]];
                        put_unaligned(cpu_to_le32(v), (s32 *)p);
                        p += 4;
index 53e7de7cb9e25e6861f1acb5e3438e590b2e70ad..20f9a653444c21d0ef89f4561d4d68544dff4bf0 100644 (file)
@@ -87,6 +87,9 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
        { 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 },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS },
index 4c0ffca97befd61cf3cdd947138d14070c4e7895..01b937e63cf37ec1424a1aad9eee0caef682c010 100644 (file)
@@ -1271,17 +1271,52 @@ fail_leds:
        pad_input_dev = NULL;
        wacom_wac->pad_registered = false;
 fail_register_pad_input:
-       input_unregister_device(touch_input_dev);
+       if (touch_input_dev)
+               input_unregister_device(touch_input_dev);
        wacom_wac->touch_input = NULL;
        wacom_wac->touch_registered = false;
 fail_register_touch_input:
-       input_unregister_device(pen_input_dev);
+       if (pen_input_dev)
+               input_unregister_device(pen_input_dev);
        wacom_wac->pen_input = NULL;
        wacom_wac->pen_registered = false;
 fail_register_pen_input:
        return error;
 }
 
+/*
+ * Not all devices report physical dimensions from HID.
+ * Compute the default from hardcoded logical dimension
+ * and resolution before driver overwrites them.
+ */
+static void wacom_set_default_phy(struct wacom_features *features)
+{
+       if (features->x_resolution) {
+               features->x_phy = (features->x_max * 100) /
+                                       features->x_resolution;
+               features->y_phy = (features->y_max * 100) /
+                                       features->y_resolution;
+       }
+}
+
+static void wacom_calculate_res(struct wacom_features *features)
+{
+       /* set unit to "100th of a mm" for devices not reported by HID */
+       if (!features->unit) {
+               features->unit = 0x11;
+               features->unitExpo = -3;
+       }
+
+       features->x_resolution = wacom_calc_hid_res(features->x_max,
+                                                   features->x_phy,
+                                                   features->unit,
+                                                   features->unitExpo);
+       features->y_resolution = wacom_calc_hid_res(features->y_max,
+                                                   features->y_phy,
+                                                   features->unit,
+                                                   features->unitExpo);
+}
+
 static void wacom_wireless_work(struct work_struct *work)
 {
        struct wacom *wacom = container_of(work, struct wacom, work);
@@ -1339,6 +1374,8 @@ static void wacom_wireless_work(struct work_struct *work)
                if (wacom_wac1->features.type != INTUOSHT &&
                    wacom_wac1->features.type != BAMBOO_PT)
                        wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD;
+               wacom_set_default_phy(&wacom_wac1->features);
+               wacom_calculate_res(&wacom_wac1->features);
                snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen",
                         wacom_wac1->features.name);
                snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
@@ -1357,7 +1394,9 @@ static void wacom_wireless_work(struct work_struct *work)
                        wacom_wac2->features =
                                *((struct wacom_features *)id->driver_data);
                        wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
+                       wacom_set_default_phy(&wacom_wac2->features);
                        wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
+                       wacom_calculate_res(&wacom_wac2->features);
                        snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX,
                                 "%s (WL) Finger",wacom_wac2->features.name);
                        snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
@@ -1405,39 +1444,6 @@ void wacom_battery_work(struct work_struct *work)
        }
 }
 
-/*
- * Not all devices report physical dimensions from HID.
- * Compute the default from hardcoded logical dimension
- * and resolution before driver overwrites them.
- */
-static void wacom_set_default_phy(struct wacom_features *features)
-{
-       if (features->x_resolution) {
-               features->x_phy = (features->x_max * 100) /
-                                       features->x_resolution;
-               features->y_phy = (features->y_max * 100) /
-                                       features->y_resolution;
-       }
-}
-
-static void wacom_calculate_res(struct wacom_features *features)
-{
-       /* set unit to "100th of a mm" for devices not reported by HID */
-       if (!features->unit) {
-               features->unit = 0x11;
-               features->unitExpo = -3;
-       }
-
-       features->x_resolution = wacom_calc_hid_res(features->x_max,
-                                                   features->x_phy,
-                                                   features->unit,
-                                                   features->unitExpo);
-       features->y_resolution = wacom_calc_hid_res(features->y_max,
-                                                   features->y_phy,
-                                                   features->unit,
-                                                   features->unitExpo);
-}
-
 static size_t wacom_compute_pktlen(struct hid_device *hdev)
 {
        struct hid_report_enum *report_enum;
index 232da89f4e886fe02b82d452c1a0868f0b65b967..0d244239e55def103f786254f3f617a84b2f0ba2 100644 (file)
@@ -2213,6 +2213,9 @@ void wacom_setup_device_quirks(struct wacom *wacom)
                        features->x_max = 4096;
                        features->y_max = 4096;
                }
+               else if (features->pktlen == WACOM_PKGLEN_BBTOUCH) {
+                       features->device_type |= WACOM_DEVICETYPE_PAD;
+               }
        }
 
        /*
index 37c16afe007a0524eaacb5edcae9399bebfae897..c8487894b31236cefd761b24cac48fb4e17e6d52 100644 (file)
@@ -929,6 +929,21 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
 
 MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);
 
+static struct dmi_system_id i8k_blacklist_dmi_table[] __initdata = {
+       {
+               /*
+                * CPU fan speed going up and down on Dell Studio XPS 8100
+                * for unknown reasons.
+                */
+               .ident = "Dell Studio XPS 8100",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8100"),
+               },
+       },
+       { }
+};
+
 /*
  * Probe for the presence of a supported laptop.
  */
@@ -940,7 +955,8 @@ static int __init i8k_probe(void)
        /*
         * Get DMI information
         */
-       if (!dmi_check_system(i8k_dmi_table)) {
+       if (!dmi_check_system(i8k_dmi_table) ||
+           dmi_check_system(i8k_blacklist_dmi_table)) {
                if (!ignore_dmi && !force)
                        return -ENODEV;
 
index 9b55e673b67caf1365c7452ce51a22a37510af02..85d106fe3ce8628061901b53240e546a884cbea0 100644 (file)
@@ -582,6 +582,7 @@ static const struct of_device_id g762_dt_match[] = {
        { .compatible = "gmt,g763" },
        { },
 };
+MODULE_DEVICE_TABLE(of, g762_dt_match);
 
 /*
  * Grab clock (a required property), enable it, get (fixed) clock frequency
index 28fcb2e246d55a7acc52703e434b98de3e22c45b..fbfc02bb2cfa13c5bc22ece3a47a3cac1af07005 100644 (file)
@@ -195,7 +195,7 @@ abort:
 }
 
 static int nct7802_write_voltage(struct nct7802_data *data, int nr, int index,
-                                unsigned int voltage)
+                                unsigned long voltage)
 {
        int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr];
        int err;
index b77b82f244800628843c103ae7dfcf157bd774ce..08ff89d222e5ff79a3c5cf37fa1b7729f70fe303 100644 (file)
@@ -412,8 +412,9 @@ static ssize_t show_pwm(struct device *dev,
        return sprintf(buf, "%d\n", val);
 }
 
-static ssize_t store_mode(struct device *dev, struct device_attribute *devattr,
-                         const char *buf, size_t count)
+static ssize_t store_enable(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf, size_t count)
 {
        int index = to_sensor_dev_attr(devattr)->index;
        struct nct7904_data *data = dev_get_drvdata(dev);
@@ -422,18 +423,18 @@ static ssize_t store_mode(struct device *dev, struct device_attribute *devattr,
 
        if (kstrtoul(buf, 10, &val) < 0)
                return -EINVAL;
-       if (val > 1 || (val && !data->fan_mode[index]))
+       if (val < 1 || val > 2 || (val == 2 && !data->fan_mode[index]))
                return -EINVAL;
 
        ret = nct7904_write_reg(data, BANK_3, FANCTL1_FMR_REG + index,
-                               val ? data->fan_mode[index] : 0);
+                               val == 2 ? data->fan_mode[index] : 0);
 
        return ret ? ret : count;
 }
 
-/* Return 0 for manual mode or 1 for SmartFan mode */
-static ssize_t show_mode(struct device *dev,
-                        struct device_attribute *devattr, char *buf)
+/* Return 1 for manual mode or 2 for SmartFan mode */
+static ssize_t show_enable(struct device *dev,
+                          struct device_attribute *devattr, char *buf)
 {
        int index = to_sensor_dev_attr(devattr)->index;
        struct nct7904_data *data = dev_get_drvdata(dev);
@@ -443,36 +444,36 @@ static ssize_t show_mode(struct device *dev,
        if (val < 0)
                return val;
 
-       return sprintf(buf, "%d\n", val ? 1 : 0);
+       return sprintf(buf, "%d\n", val ? 2 : 1);
 }
 
 /* 2 attributes per channel: pwm and mode */
-static SENSOR_DEVICE_ATTR(fan1_pwm, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR,
                        show_pwm, store_pwm, 0);
-static SENSOR_DEVICE_ATTR(fan1_mode, S_IRUGO | S_IWUSR,
-                       show_mode, store_mode, 0);
-static SENSOR_DEVICE_ATTR(fan2_pwm, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+                       show_enable, store_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR,
                        show_pwm, store_pwm, 1);
-static SENSOR_DEVICE_ATTR(fan2_mode, S_IRUGO | S_IWUSR,
-                       show_mode, store_mode, 1);
-static SENSOR_DEVICE_ATTR(fan3_pwm, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
+                       show_enable, store_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR,
                        show_pwm, store_pwm, 2);
-static SENSOR_DEVICE_ATTR(fan3_mode, S_IRUGO | S_IWUSR,
-                       show_mode, store_mode, 2);
-static SENSOR_DEVICE_ATTR(fan4_pwm, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
+                       show_enable, store_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR,
                        show_pwm, store_pwm, 3);
-static SENSOR_DEVICE_ATTR(fan4_mode, S_IRUGO | S_IWUSR,
-                       show_mode, store_mode, 3);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR,
+                       show_enable, store_enable, 3);
 
 static struct attribute *nct7904_fanctl_attrs[] = {
-       &sensor_dev_attr_fan1_pwm.dev_attr.attr,
-       &sensor_dev_attr_fan1_mode.dev_attr.attr,
-       &sensor_dev_attr_fan2_pwm.dev_attr.attr,
-       &sensor_dev_attr_fan2_mode.dev_attr.attr,
-       &sensor_dev_attr_fan3_pwm.dev_attr.attr,
-       &sensor_dev_attr_fan3_mode.dev_attr.attr,
-       &sensor_dev_attr_fan4_pwm.dev_attr.attr,
-       &sensor_dev_attr_fan4_mode.dev_attr.attr,
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm2.dev_attr.attr,
+       &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm3.dev_attr.attr,
+       &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm4.dev_attr.attr,
+       &sensor_dev_attr_pwm4_enable.dev_attr.attr,
        NULL
 };
 
@@ -574,6 +575,7 @@ static const struct i2c_device_id nct7904_id[] = {
        {"nct7904", 0},
        {}
 };
+MODULE_DEVICE_TABLE(i2c, nct7904_id);
 
 static struct i2c_driver nct7904_driver = {
        .class = I2C_CLASS_HWMON,
index af162b4c7a6d9b8b30756c53147eb3de458b3d5e..025686d4164058498216862d37af9ad114fe4fa2 100644 (file)
@@ -692,7 +692,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, iface);
 
-       dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
+       dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Controller, "
                "regs_base@%p\n", iface->regs_base);
 
        return 0;
@@ -735,6 +735,6 @@ subsys_initcall(i2c_bfin_twi_init);
 module_exit(i2c_bfin_twi_exit);
 
 MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
-MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
+MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Controller Driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:i2c-bfin-twi");
index d1c22e3fdd146a34d96adcdd35b81a6e15984824..fc9bf7f30e355dfadfcadd4f7d8f187f818e9566 100644 (file)
@@ -1247,7 +1247,14 @@ static void omap_i2c_prepare_recovery(struct i2c_adapter *adap)
        u32 reg;
 
        reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+       /* enable test mode */
        reg |= OMAP_I2C_SYSTEST_ST_EN;
+       /* select SDA/SCL IO mode */
+       reg |= 3 << OMAP_I2C_SYSTEST_TMODE_SHIFT;
+       /* set SCL to high-impedance state (reset value is 0) */
+       reg |= OMAP_I2C_SYSTEST_SCL_O;
+       /* set SDA to high-impedance state (reset value is 0) */
+       reg |= OMAP_I2C_SYSTEST_SDA_O;
        omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
 }
 
@@ -1257,7 +1264,11 @@ static void omap_i2c_unprepare_recovery(struct i2c_adapter *adap)
        u32 reg;
 
        reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+       /* restore reset values */
        reg &= ~OMAP_I2C_SYSTEST_ST_EN;
+       reg &= ~OMAP_I2C_SYSTEST_TMODE_MASK;
+       reg &= ~OMAP_I2C_SYSTEST_SCL_O;
+       reg &= ~OMAP_I2C_SYSTEST_SDA_O;
        omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
 }
 
index e6d4935161e4902762f6042847838428ec34faf2..c83e4d13cfc5c402dfdea64df08f399ab486822b 100644 (file)
@@ -567,6 +567,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
        if (bri->prepare_recovery)
                bri->prepare_recovery(adap);
 
+       bri->set_scl(adap, val);
+       ndelay(RECOVERY_NDELAY);
+
        /*
         * By this time SCL is high, as we need to give 9 falling-rising edges
         */
@@ -597,7 +600,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
 
 int i2c_generic_scl_recovery(struct i2c_adapter *adap)
 {
-       adap->bus_recovery_info->set_scl(adap, 1);
        return i2c_generic_recovery(adap);
 }
 EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);
@@ -1338,13 +1340,17 @@ static int of_dev_node_match(struct device *dev, void *data)
 struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
 {
        struct device *dev;
+       struct i2c_client *client;
 
-       dev = bus_find_device(&i2c_bus_type, NULL, node,
-                                        of_dev_node_match);
+       dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
        if (!dev)
                return NULL;
 
-       return i2c_verify_client(dev);
+       client = i2c_verify_client(dev);
+       if (!client)
+               put_device(dev);
+
+       return client;
 }
 EXPORT_SYMBOL(of_find_i2c_device_by_node);
 
@@ -1352,13 +1358,17 @@ EXPORT_SYMBOL(of_find_i2c_device_by_node);
 struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
 {
        struct device *dev;
+       struct i2c_adapter *adapter;
 
-       dev = bus_find_device(&i2c_bus_type, NULL, node,
-                                        of_dev_node_match);
+       dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
        if (!dev)
                return NULL;
 
-       return i2c_verify_adapter(dev);
+       adapter = i2c_verify_adapter(dev);
+       if (!adapter)
+               put_device(dev);
+
+       return adapter;
 }
 EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
 #else
index 8223746546093c7a08f4bdfc8425459d88fe1a52..1da44961477953038e78409169f80a3f4884f89a 100644 (file)
@@ -80,9 +80,6 @@ static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj
        struct eeprom_data *eeprom;
        unsigned long flags;
 
-       if (off + count > attr->size)
-               return -EFBIG;
-
        eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
 
        spin_lock_irqsave(&eeprom->buffer_lock, flags);
@@ -98,9 +95,6 @@ static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kob
        struct eeprom_data *eeprom;
        unsigned long flags;
 
-       if (off + count > attr->size)
-               return -EFBIG;
-
        eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
 
        spin_lock_irqsave(&eeprom->buffer_lock, flags);
index e8e2077c7244b5623efc8cd07521a9105dfbe192..13ea1ea23328501f4969c5453e603cf67e5b81b2 100644 (file)
@@ -557,21 +557,21 @@ static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
        if (src & MMA8452_TRANSIENT_SRC_XTRANSE)
                iio_push_event(indio_dev,
                               IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
-                                                 IIO_EV_TYPE_THRESH,
+                                                 IIO_EV_TYPE_MAG,
                                                  IIO_EV_DIR_RISING),
                               ts);
 
        if (src & MMA8452_TRANSIENT_SRC_YTRANSE)
                iio_push_event(indio_dev,
                               IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y,
-                                                 IIO_EV_TYPE_THRESH,
+                                                 IIO_EV_TYPE_MAG,
                                                  IIO_EV_DIR_RISING),
                               ts);
 
        if (src & MMA8452_TRANSIENT_SRC_ZTRANSE)
                iio_push_event(indio_dev,
                               IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z,
-                                                 IIO_EV_TYPE_THRESH,
+                                                 IIO_EV_TYPE_MAG,
                                                  IIO_EV_DIR_RISING),
                               ts);
 }
@@ -644,7 +644,7 @@ static int mma8452_reg_access_dbg(struct iio_dev *indio_dev,
 
 static const struct iio_event_spec mma8452_transient_event[] = {
        {
-               .type = IIO_EV_TYPE_THRESH,
+               .type = IIO_EV_TYPE_MAG,
                .dir = IIO_EV_DIR_RISING,
                .mask_separate = BIT(IIO_EV_INFO_ENABLE),
                .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
index 8d9c9b9215ddc1ef5530df512d475a618cb71d8f..d819823f725747e5cd4ac8bcb50d3d833093ed2c 100644 (file)
@@ -299,6 +299,8 @@ static int mcp320x_probe(struct spi_device *spi)
        indio_dev->channels = chip_info->channels;
        indio_dev->num_channels = chip_info->num_channels;
 
+       adc->chip_info = chip_info;
+
        adc->transfer[0].tx_buf = &adc->tx_buf;
        adc->transfer[0].len = sizeof(adc->tx_buf);
        adc->transfer[1].rx_buf = adc->rx_buf;
index 480f335a0f9faee31bc6b2ac14f7899f18d6c9be..819632bf1fda7fee8fddd2acb3c02d9ff112b1ff 100644 (file)
@@ -635,7 +635,7 @@ static int vf610_adc_reg_access(struct iio_dev *indio_dev,
        struct vf610_adc *info = iio_priv(indio_dev);
 
        if ((readval == NULL) ||
-               (!(reg % 4) || (reg > VF610_REG_ADC_PCTL)))
+               ((reg % 4) || (reg > VF610_REG_ADC_PCTL)))
                return -EINVAL;
 
        *readval = readl(info->regs + reg);
index c1a218236be5c54f9829436cbb606c0d758cef74..11a027adc204aeb630c66707eaf9d5d0ce169ebb 100644 (file)
@@ -200,7 +200,7 @@ static int stk3310_read_event(struct iio_dev *indio_dev,
                              int *val, int *val2)
 {
        u8 reg;
-       u16 buf;
+       __be16 buf;
        int ret;
        struct stk3310_data *data = iio_priv(indio_dev);
 
@@ -222,7 +222,7 @@ static int stk3310_read_event(struct iio_dev *indio_dev,
                dev_err(&data->client->dev, "register read failed\n");
                return ret;
        }
-       *val = swab16(buf);
+       *val = be16_to_cpu(buf);
 
        return IIO_VAL_INT;
 }
@@ -235,7 +235,7 @@ static int stk3310_write_event(struct iio_dev *indio_dev,
                               int val, int val2)
 {
        u8 reg;
-       u16 buf;
+       __be16 buf;
        int ret;
        unsigned int index;
        struct stk3310_data *data = iio_priv(indio_dev);
@@ -252,7 +252,7 @@ static int stk3310_write_event(struct iio_dev *indio_dev,
        else
                return -EINVAL;
 
-       buf = swab16(val);
+       buf = cpu_to_be16(val);
        ret = regmap_bulk_write(data->regmap, reg, &buf, 2);
        if (ret < 0)
                dev_err(&client->dev, "failed to set PS threshold!\n");
@@ -301,7 +301,7 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
                            int *val, int *val2, long mask)
 {
        u8 reg;
-       u16 buf;
+       __be16 buf;
        int ret;
        unsigned int index;
        struct stk3310_data *data = iio_priv(indio_dev);
@@ -322,7 +322,7 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
                        mutex_unlock(&data->lock);
                        return ret;
                }
-               *val = swab16(buf);
+               *val = be16_to_cpu(buf);
                mutex_unlock(&data->lock);
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_INT_TIME:
@@ -608,13 +608,7 @@ static int stk3310_probe(struct i2c_client *client,
        if (ret < 0)
                return ret;
 
-       ret = iio_device_register(indio_dev);
-       if (ret < 0) {
-               dev_err(&client->dev, "device_register failed\n");
-               stk3310_set_state(data, STK3310_STATE_STANDBY);
-       }
-
-       if (client->irq <= 0)
+       if (client->irq < 0)
                client->irq = stk3310_gpio_probe(client);
 
        if (client->irq >= 0) {
@@ -629,6 +623,12 @@ static int stk3310_probe(struct i2c_client *client,
                                        client->irq);
        }
 
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(&client->dev, "device_register failed\n");
+               stk3310_set_state(data, STK3310_STATE_STANDBY);
+       }
+
        return ret;
 }
 
index dcadfc4f06619a1a147d560581bb7bfabdd3f663..efb9350b0d766a0915a2c091c04b9bdea15c5d4e 100644 (file)
@@ -90,6 +90,7 @@ config IIO_ST_MAGN_SPI_3AXIS
 config BMC150_MAGN
        tristate "Bosch BMC150 Magnetometer Driver"
        depends on I2C
+       select REGMAP_I2C
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
index d4c1788699911e934fc3c1baffa3de8928ac26a6..1347a1f2e46f8194bad0bfe49bd91ea6a948ac8e 100644 (file)
@@ -706,11 +706,11 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
                goto err_poweroff;
        }
        if (chip_id != BMC150_MAGN_CHIP_ID_VAL) {
-               dev_err(&data->client->dev, "Invalid chip id 0x%x\n", ret);
+               dev_err(&data->client->dev, "Invalid chip id 0x%x\n", chip_id);
                ret = -ENODEV;
                goto err_poweroff;
        }
-       dev_dbg(&data->client->dev, "Chip id %x\n", ret);
+       dev_dbg(&data->client->dev, "Chip id %x\n", chip_id);
 
        preset = bmc150_magn_presets_table[BMC150_MAGN_DEFAULT_PRESET];
        ret = bmc150_magn_set_odr(data, preset.odr);
index d927397a6ef77e1f2e72b576108f475c5d40b2ef..706ebfd6297fa7c0a311a80bfcb431b533d2cc70 100644 (file)
@@ -202,8 +202,8 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set)
                coil_bit = MMC35240_CTRL0_RESET_BIT;
 
        return regmap_update_bits(data->regmap, MMC35240_REG_CTRL0,
-                                 MMC35240_CTRL0_REFILL_BIT,
-                                 coil_bit);
+                                 coil_bit, coil_bit);
+
 }
 
 static int mmc35240_init(struct mmc35240_data *data)
@@ -222,14 +222,15 @@ static int mmc35240_init(struct mmc35240_data *data)
 
        /*
         * make sure we restore sensor characteristics, by doing
-        * a RESET/SET sequence
+        * a SET/RESET sequence, the axis polarity being naturally
+        * aligned after RESET
         */
-       ret = mmc35240_hw_set(data, false);
+       ret = mmc35240_hw_set(data, true);
        if (ret < 0)
                return ret;
        usleep_range(MMC53240_WAIT_SET_RESET, MMC53240_WAIT_SET_RESET + 1);
 
-       ret = mmc35240_hw_set(data, true);
+       ret = mmc35240_hw_set(data, false);
        if (ret < 0)
                return ret;
 
@@ -503,6 +504,7 @@ static int mmc35240_probe(struct i2c_client *client,
        }
 
        data = iio_priv(indio_dev);
+       i2c_set_clientdata(client, indio_dev);
        data->client = client;
        data->regmap = regmap;
        data->res = MMC35240_16_BITS_SLOW;
index cb2e8ad8bfdcd02e75b9ea4f82e31c598e95109e..7a2b639eaa96e2ea440f3102c5da101d41edcd2b 100644 (file)
@@ -204,7 +204,7 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
                *val = ret;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_OFFSET:
-               *val = 13657;
+               *val = -13657;
                *val2 = 500000;
                return IIO_VAL_INT_PLUS_MICRO;
        case IIO_CHAN_INFO_SCALE:
index b1b73232f21702161d7dc068f08e23e6759e04e8..bbbe0184e5922f6dab1fce7c56a92d1422da986e 100644 (file)
@@ -736,6 +736,10 @@ static struct ib_mr *iwch_get_dma_mr(struct ib_pd *pd, int acc)
        /*
         * T3 only supports 32 bits of size.
         */
+       if (sizeof(phys_addr_t) > 4) {
+               pr_warn_once(MOD "Cannot support dma_mrs on this platform.\n");
+               return ERR_PTR(-ENOTSUPP);
+       }
        bl.size = 0xffffffff;
        bl.addr = 0;
        kva = 0;
index 2d7e503d13cb5b9c2855936ce162f41d49ca0ced..871dbe56216a27e75ee64a1e4646ca027dd22a27 100644 (file)
@@ -31,6 +31,8 @@
  * SOFTWARE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/idr.h>
@@ -399,8 +401,8 @@ static int ipath_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        u32 bar0 = 0, bar1 = 0;
 
 #ifdef CONFIG_X86_64
-       if (WARN(pat_enabled(),
-                "ipath needs PAT disabled, boot with nopat kernel parameter\n")) {
+       if (pat_enabled()) {
+               pr_warn("ipath needs PAT disabled, boot with nopat kernel parameter\n");
                ret = -ENODEV;
                goto bail;
        }
index b396344fae16af33153f0625104d95c17f488a8d..6a36338593cd0a1c09b1ad67c1d7d57f856b0e93 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_H__
 #define __OCRDMA_H__
index 1554cca5712aafd5659d1cfb80bafff7095f67ca..430b1350fe96ecd1eb16a67f18c2bc3a8e6afa80 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_ABI_H__
 #define __OCRDMA_ABI_H__
index 29b27675dd709e8271708c6ca91cc9deb0a1076e..44766fee1f4e2cacb2d971f7858ad6e3eb4c4875 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <net/neighbour.h>
 #include <net/netevent.h>
index cf366fe03cb822580fe96b69e5873ad255a34632..04a30ae674739b87dc266194f68aa27271df653e 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_AH_H__
 #define __OCRDMA_AH_H__
index 47615ff33bc6a1fb8c0c703b9f975acc6afe79c2..aab391a15db429104f52765346455ba07efa424b 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) CNA Adapters.              *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <linux/sched.h>
 #include <linux/interrupt.h>
index e905972fceb7d48ff882800390c1330367815caf..7ed885c1851e28740b81a0588493c0d0ca92bc42 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) CNA Adapters.              *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_HW_H__
 #define __OCRDMA_HW_H__
index d98a707a5eb9b3e27a51548a0fbe2ae9b893ebab..b119a3413a155574ae1eb1bdd020bb7d77e42822 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <linux/module.h>
 #include <linux/idr.h>
@@ -46,7 +61,7 @@
 MODULE_VERSION(OCRDMA_ROCE_DRV_VERSION);
 MODULE_DESCRIPTION(OCRDMA_ROCE_DRV_DESC " " OCRDMA_ROCE_DRV_VERSION);
 MODULE_AUTHOR("Emulex Corporation");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual BSD/GPL");
 
 static LIST_HEAD(ocrdma_dev_list);
 static DEFINE_SPINLOCK(ocrdma_devlist_lock);
index 02ad0aee99afc0c5e9449c4f58353e57d38903f1..80006b24aa118e752f444383fc9f4f3c3bafb191 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_SLI_H__
 #define __OCRDMA_SLI_H__
index 48d7ef51aa0c209678e0ed4bbe97bc5ff9a881d5..69334e214571b94ae0305bc8c9821aa0e261b7fe 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2014 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <rdma/ib_addr.h>
 #include <rdma/ib_pma.h>
index 091edd68a8a34678e5283b2374c58274c84580b3..c9e58d04c7b8d15c15c5d8ae4205c87cc3be521c 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2014 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_STATS_H__
 #define __OCRDMA_STATS_H__
index 5bb61eb58f2c71859969d73ac6e326d4dafc51fd..bc84cd462ecf3208e8576ad1ba1084578ddb7c29 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <linux/dma-mapping.h>
 #include <rdma/ib_verbs.h>
index b15c608efa7b03c72a2eb44e1f7b8af919db13b0..eaccb2d3cb9ff52f51fe0bbba3334053d519d047 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_VERBS_H__
 #define __OCRDMA_VERBS_H__
index 9e6ee82a8fd76f490de93d6117754e2a6657ec72..851c8219d50104105ec8d97a3ba743cb6f59626b 100644 (file)
@@ -177,7 +177,8 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
                else
                        size += ipoib_recvq_size * ipoib_max_conn_qp;
        } else
-               goto out_free_wq;
+               if (ret != -ENOSYS)
+                       goto out_free_wq;
 
        cq_attr.cqe = size;
        priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL,
index 7717009631271ea6965a7d60b9dcf3f74acdd1d6..d851e1828d6f5152e9c8ca49de9b64a3b953f180 100644 (file)
@@ -775,6 +775,17 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        ret = isert_rdma_post_recvl(isert_conn);
        if (ret)
                goto out_conn_dev;
+       /*
+        * Obtain the second reference now before isert_rdma_accept() to
+        * ensure that any initiator generated REJECT CM event that occurs
+        * asynchronously won't drop the last reference until the error path
+        * in iscsi_target_login_sess_out() does it's ->iscsit_free_conn() ->
+        * isert_free_conn() -> isert_put_conn() -> kref_put().
+        */
+       if (!kref_get_unless_zero(&isert_conn->kref)) {
+               isert_warn("conn %p connect_release is running\n", isert_conn);
+               goto out_conn_dev;
+       }
 
        ret = isert_rdma_accept(isert_conn);
        if (ret)
@@ -836,11 +847,6 @@ isert_connected_handler(struct rdma_cm_id *cma_id)
 
        isert_info("conn %p\n", isert_conn);
 
-       if (!kref_get_unless_zero(&isert_conn->kref)) {
-               isert_warn("conn %p connect_release is running\n", isert_conn);
-               return;
-       }
-
        mutex_lock(&isert_conn->mutex);
        if (isert_conn->state != ISER_CONN_FULL_FEATURE)
                isert_conn->state = ISER_CONN_UP;
index 074a65ed17bb4d595d2b48f13e0d2e03c2267bc6..766bf26601163c37aebf265160b4d3d0ce09617f 100644 (file)
@@ -71,6 +71,18 @@ static void input_leds_event(struct input_handle *handle, unsigned int type,
 {
 }
 
+static int input_leds_get_count(struct input_dev *dev)
+{
+       unsigned int led_code;
+       int count = 0;
+
+       for_each_set_bit(led_code, dev->ledbit, LED_CNT)
+               if (input_led_info[led_code].name)
+                       count++;
+
+       return count;
+}
+
 static int input_leds_connect(struct input_handler *handler,
                              struct input_dev *dev,
                              const struct input_device_id *id)
@@ -81,7 +93,7 @@ static int input_leds_connect(struct input_handler *handler,
        int led_no;
        int error;
 
-       num_leds = bitmap_weight(dev->ledbit, LED_CNT);
+       num_leds = input_leds_get_count(dev);
        if (!num_leds)
                return -ENXIO;
 
@@ -112,7 +124,7 @@ static int input_leds_connect(struct input_handler *handler,
                led->handle = &leds->handle;
                led->code = led_code;
 
-               if (WARN_ON(!input_led_info[led_code].name))
+               if (!input_led_info[led_code].name)
                        continue;
 
                led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
index 27b6a3ce18caf2e996177e6c313fff2b21a4ad19..891797ad76bccda3ae132e1fc59483b539e522ee 100644 (file)
@@ -196,7 +196,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
                if (n_buttons[i] < 1)
                        continue;
 
-               if (n_buttons[i] > 6) {
+               if (n_buttons[i] > ARRAY_SIZE(tgfx_buttons)) {
                        printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]);
                        err = -EINVAL;
                        goto err_unreg_devs;
index 10e140af5aac1a9ea309d2b237af065cc7abf684..1ac898db303afe84edd003a03129eb0f27518837 100644 (file)
@@ -292,3 +292,4 @@ module_platform_driver(axp20x_pek_driver);
 MODULE_DESCRIPTION("axp20x Power Button");
 MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:axp20x-pek");
index fc17b9592f5435238d980cc30d266a4ee399415a..10c4e3d462f112f15ec9843093c5f988d44780b9 100644 (file)
@@ -183,7 +183,8 @@ static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
        if (pdata && pdata->coexist)
                return true;
 
-       if (of_find_node_by_name(node, "codec")) {
+       node = of_find_node_by_name(node, "codec");
+       if (node) {
                of_node_put(node);
                return true;
        }
index 113d6f1516a54956f74635f7eb51231ab5490052..4d246861d692b810f3074aa7917cda86893ac6c2 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/input/mt.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
+#include <linux/dmi.h>
 
 #include "psmouse.h"
 #include "alps.h"
@@ -99,6 +100,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
 #define ALPS_FOUR_BUTTONS      0x40    /* 4 direction button present */
 #define ALPS_PS2_INTERLEAVED   0x80    /* 3-byte PS/2 packet interleaved with
                                           6-byte ALPS packet */
+#define ALPS_DELL              0x100   /* device is a Dell laptop */
 #define ALPS_BUTTONPAD         0x200   /* device is a clickpad */
 
 static const struct alps_model_info alps_model_data[] = {
@@ -251,9 +253,9 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
                return;
        }
 
-       /* Non interleaved V2 dualpoint has separate stick button bits */
+       /* Dell non interleaved V2 dualpoint has separate stick button bits */
        if (priv->proto_version == ALPS_PROTO_V2 &&
-           priv->flags == (ALPS_PASS | ALPS_DUALPOINT)) {
+           priv->flags == (ALPS_DELL | ALPS_PASS | ALPS_DUALPOINT)) {
                left |= packet[0] & 1;
                right |= packet[0] & 2;
                middle |= packet[0] & 4;
@@ -2550,6 +2552,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
        priv->byte0 = protocol->byte0;
        priv->mask0 = protocol->mask0;
        priv->flags = protocol->flags;
+       if (dmi_name_in_vendors("Dell"))
+               priv->flags |= ALPS_DELL;
 
        priv->x_max = 2000;
        priv->y_max = 1400;
index b10709f0461559c4d5ca03f47ae1d82c75663e91..30e3442518f85cfe06732e0f331962458396008c 100644 (file)
@@ -2,6 +2,7 @@
  * Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver
  *
  * Copyright (C) 2008     Henrik Rydberg (rydberg@euromail.se)
+ * Copyright (C) 2015      John Horan (knasher@gmail.com)
  *
  * The USB initialization and package decoding was made by
  * Scott Shawcroft as part of the touchd user-space driver project:
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI   0x0290
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO    0x0291
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS    0x0292
+/* MacbookPro12,1 (2015) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI   0x0272
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO    0x0273
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS    0x0274
 
 #define BCM5974_DEVICE(prod) {                                 \
        .match_flags = (USB_DEVICE_ID_MATCH_DEVICE |            \
@@ -152,6 +157,10 @@ static const struct usb_device_id bcm5974_table[] = {
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
+       /* MacbookPro12,1 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
        /* Terminating entry */
        {}
 };
@@ -180,21 +189,47 @@ struct bt_data {
 enum tp_type {
        TYPE1,                  /* plain trackpad */
        TYPE2,                  /* button integrated in trackpad */
-       TYPE3                   /* additional header fields since June 2013 */
+       TYPE3,                  /* additional header fields since June 2013 */
+       TYPE4                   /* additional header field for pressure data */
 };
 
 /* trackpad finger data offsets, le16-aligned */
-#define FINGER_TYPE1           (13 * sizeof(__le16))
-#define FINGER_TYPE2           (15 * sizeof(__le16))
-#define FINGER_TYPE3           (19 * sizeof(__le16))
+#define HEADER_TYPE1           (13 * sizeof(__le16))
+#define HEADER_TYPE2           (15 * sizeof(__le16))
+#define HEADER_TYPE3           (19 * sizeof(__le16))
+#define HEADER_TYPE4           (23 * sizeof(__le16))
 
 /* trackpad button data offsets */
+#define BUTTON_TYPE1           0
 #define BUTTON_TYPE2           15
 #define BUTTON_TYPE3           23
+#define BUTTON_TYPE4           31
 
 /* list of device capability bits */
 #define HAS_INTEGRATED_BUTTON  1
 
+/* trackpad finger data block size */
+#define FSIZE_TYPE1            (14 * sizeof(__le16))
+#define FSIZE_TYPE2            (14 * sizeof(__le16))
+#define FSIZE_TYPE3            (14 * sizeof(__le16))
+#define FSIZE_TYPE4            (15 * sizeof(__le16))
+
+/* offset from header to finger struct */
+#define DELTA_TYPE1            (0 * sizeof(__le16))
+#define DELTA_TYPE2            (0 * sizeof(__le16))
+#define DELTA_TYPE3            (0 * sizeof(__le16))
+#define DELTA_TYPE4            (1 * sizeof(__le16))
+
+/* usb control message mode switch data */
+#define USBMSG_TYPE1           8, 0x300, 0, 0, 0x1, 0x8
+#define USBMSG_TYPE2           8, 0x300, 0, 0, 0x1, 0x8
+#define USBMSG_TYPE3           8, 0x300, 0, 0, 0x1, 0x8
+#define USBMSG_TYPE4           2, 0x302, 2, 1, 0x1, 0x0
+
+/* Wellspring initialization constants */
+#define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID                1
+#define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID       9
+
 /* trackpad finger structure, le16-aligned */
 struct tp_finger {
        __le16 origin;          /* zero when switching track finger */
@@ -207,14 +242,13 @@ struct tp_finger {
        __le16 orientation;     /* 16384 when point, else 15 bit angle */
        __le16 touch_major;     /* touch area, major axis */
        __le16 touch_minor;     /* touch area, minor axis */
-       __le16 unused[3];       /* zeros */
+       __le16 unused[2];       /* zeros */
+       __le16 pressure;        /* pressure on forcetouch touchpad */
        __le16 multi;           /* one finger: varies, more fingers: constant */
 } __attribute__((packed,aligned(2)));
 
 /* trackpad finger data size, empirically at least ten fingers */
 #define MAX_FINGERS            16
-#define SIZEOF_FINGER          sizeof(struct tp_finger)
-#define SIZEOF_ALL_FINGERS     (MAX_FINGERS * SIZEOF_FINGER)
 #define MAX_FINGER_ORIENTATION 16384
 
 /* device-specific parameters */
@@ -232,8 +266,17 @@ struct bcm5974_config {
        int bt_datalen;         /* data length of the button interface */
        int tp_ep;              /* the endpoint of the trackpad interface */
        enum tp_type tp_type;   /* type of trackpad interface */
-       int tp_offset;          /* offset to trackpad finger data */
+       int tp_header;          /* bytes in header block */
        int tp_datalen;         /* data length of the trackpad interface */
+       int tp_button;          /* offset to button data */
+       int tp_fsize;           /* bytes in single finger block */
+       int tp_delta;           /* offset from header to finger struct */
+       int um_size;            /* usb control message length */
+       int um_req_val;         /* usb control message value */
+       int um_req_idx;         /* usb control message index */
+       int um_switch_idx;      /* usb control message mode switch index */
+       int um_switch_on;       /* usb control message mode switch on */
+       int um_switch_off;      /* usb control message mode switch off */
        struct bcm5974_param p; /* finger pressure limits */
        struct bcm5974_param w; /* finger width limits */
        struct bcm5974_param x; /* horizontal limits */
@@ -259,6 +302,24 @@ struct bcm5974 {
        int slots[MAX_FINGERS];                         /* slot assignments */
 };
 
+/* trackpad finger block data, le16-aligned */
+static const struct tp_finger *get_tp_finger(const struct bcm5974 *dev, int i)
+{
+       const struct bcm5974_config *c = &dev->cfg;
+       u8 *f_base = dev->tp_data + c->tp_header + c->tp_delta;
+
+       return (const struct tp_finger *)(f_base + i * c->tp_fsize);
+}
+
+#define DATAFORMAT(type)                               \
+       type,                                           \
+       HEADER_##type,                                  \
+       HEADER_##type + (MAX_FINGERS) * (FSIZE_##type), \
+       BUTTON_##type,                                  \
+       FSIZE_##type,                                   \
+       DELTA_##type,                                   \
+       USBMSG_##type
+
 /* logical signal quality */
 #define SN_PRESSURE    45              /* pressure signal-to-noise ratio */
 #define SN_WIDTH       25              /* width signal-to-noise ratio */
@@ -273,7 +334,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING_JIS,
                0,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE1),
                { SN_PRESSURE, 0, 256 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4824, 5342 },
@@ -286,7 +347,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING2_JIS,
                0,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE1),
                { SN_PRESSURE, 0, 256 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4824, 4824 },
@@ -299,7 +360,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING3_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4460, 5166 },
@@ -312,7 +373,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING4_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4620, 5140 },
@@ -325,7 +386,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4616, 5112 },
@@ -338,7 +399,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING5_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4415, 5050 },
@@ -351,7 +412,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING6_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4620, 5140 },
@@ -364,7 +425,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4750, 5280 },
@@ -377,7 +438,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4620, 5140 },
@@ -390,7 +451,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING7_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4750, 5280 },
@@ -403,7 +464,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4750, 5280 },
@@ -416,13 +477,26 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING8_JIS,
                HAS_INTEGRATED_BUTTON,
                0, sizeof(struct bt_data),
-               0x83, TYPE3, FINGER_TYPE3, FINGER_TYPE3 + SIZEOF_ALL_FINGERS,
+               0x83, DATAFORMAT(TYPE3),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4620, 5140 },
                { SN_COORD, -150, 6600 },
                { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
+       {
+               USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI,
+               USB_DEVICE_ID_APPLE_WELLSPRING9_ISO,
+               USB_DEVICE_ID_APPLE_WELLSPRING9_JIS,
+               HAS_INTEGRATED_BUTTON,
+               0, sizeof(struct bt_data),
+               0x83, DATAFORMAT(TYPE4),
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4828, 5345 },
+               { SN_COORD, -203, 6803 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
+       },
        {}
 };
 
@@ -549,19 +623,18 @@ static int report_tp_state(struct bcm5974 *dev, int size)
        struct input_dev *input = dev->input;
        int raw_n, i, n = 0;
 
-       if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
+       if (size < c->tp_header || (size - c->tp_header) % c->tp_fsize != 0)
                return -EIO;
 
-       /* finger data, le16-aligned */
-       f = (const struct tp_finger *)(dev->tp_data + c->tp_offset);
-       raw_n = (size - c->tp_offset) / SIZEOF_FINGER;
+       raw_n = (size - c->tp_header) / c->tp_fsize;
 
        for (i = 0; i < raw_n; i++) {
-               if (raw2int(f[i].touch_major) == 0)
+               f = get_tp_finger(dev, i);
+               if (raw2int(f->touch_major) == 0)
                        continue;
-               dev->pos[n].x = raw2int(f[i].abs_x);
-               dev->pos[n].y = c->y.min + c->y.max - raw2int(f[i].abs_y);
-               dev->index[n++] = &f[i];
+               dev->pos[n].x = raw2int(f->abs_x);
+               dev->pos[n].y = c->y.min + c->y.max - raw2int(f->abs_y);
+               dev->index[n++] = f;
        }
 
        input_mt_assign_slots(input, dev->slots, dev->pos, n, 0);
@@ -572,32 +645,22 @@ static int report_tp_state(struct bcm5974 *dev, int size)
 
        input_mt_sync_frame(input);
 
-       report_synaptics_data(input, c, f, raw_n);
+       report_synaptics_data(input, c, get_tp_finger(dev, 0), raw_n);
 
-       /* type 2 reports button events via ibt only */
-       if (c->tp_type == TYPE2) {
-               int ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
+       /* later types report button events via integrated button only */
+       if (c->caps & HAS_INTEGRATED_BUTTON) {
+               int ibt = raw2int(dev->tp_data[c->tp_button]);
                input_report_key(input, BTN_LEFT, ibt);
        }
 
-       if (c->tp_type == TYPE3)
-               input_report_key(input, BTN_LEFT, dev->tp_data[BUTTON_TYPE3]);
-
        input_sync(input);
 
        return 0;
 }
 
-/* Wellspring initialization constants */
-#define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID                1
-#define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID       9
-#define BCM5974_WELLSPRING_MODE_REQUEST_VALUE          0x300
-#define BCM5974_WELLSPRING_MODE_REQUEST_INDEX          0
-#define BCM5974_WELLSPRING_MODE_VENDOR_VALUE           0x01
-#define BCM5974_WELLSPRING_MODE_NORMAL_VALUE           0x08
-
 static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
 {
+       const struct bcm5974_config *c = &dev->cfg;
        int retval = 0, size;
        char *data;
 
@@ -605,7 +668,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
        if (dev->cfg.tp_type == TYPE3)
                return 0;
 
-       data = kmalloc(8, GFP_KERNEL);
+       data = kmalloc(c->um_size, GFP_KERNEL);
        if (!data) {
                dev_err(&dev->intf->dev, "out of memory\n");
                retval = -ENOMEM;
@@ -616,28 +679,24 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
        size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                        BCM5974_WELLSPRING_MODE_READ_REQUEST_ID,
                        USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
-                       BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
+                       c->um_req_val, c->um_req_idx, data, c->um_size, 5000);
 
-       if (size != 8) {
+       if (size != c->um_size) {
                dev_err(&dev->intf->dev, "could not read from device\n");
                retval = -EIO;
                goto out;
        }
 
        /* apply the mode switch */
-       data[0] = on ?
-               BCM5974_WELLSPRING_MODE_VENDOR_VALUE :
-               BCM5974_WELLSPRING_MODE_NORMAL_VALUE;
+       data[c->um_switch_idx] = on ? c->um_switch_on : c->um_switch_off;
 
        /* write configuration */
        size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                        BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID,
                        USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
-                       BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
+                       c->um_req_val, c->um_req_idx, data, c->um_size, 5000);
 
-       if (size != 8) {
+       if (size != c->um_size) {
                dev_err(&dev->intf->dev, "could not write to device\n");
                retval = -EIO;
                goto out;
index ce3d40004458c87392339472f654462fae7cf0bc..2955f1d0ca6c4c9137f786028ca36bff706beab2 100644 (file)
@@ -783,19 +783,26 @@ static int elantech_packet_check_v4(struct psmouse *psmouse)
        struct elantech_data *etd = psmouse->private;
        unsigned char *packet = psmouse->packet;
        unsigned char packet_type = packet[3] & 0x03;
+       unsigned int ic_version;
        bool sanity_check;
 
        if (etd->tp_dev && (packet[3] & 0x0f) == 0x06)
                return PACKET_TRACKPOINT;
 
+       /* This represents the version of IC body. */
+       ic_version = (etd->fw_version & 0x0f0000) >> 16;
+
        /*
         * Sanity check based on the constant bits of a packet.
         * The constant bits change depending on the value of
-        * the hardware flag 'crc_enabled' but are the same for
-        * every packet, regardless of the type.
+        * the hardware flag 'crc_enabled' and the version of
+        * the IC body, but are the same for every packet,
+        * regardless of the type.
         */
        if (etd->crc_enabled)
                sanity_check = ((packet[3] & 0x08) == 0x00);
+       else if (ic_version == 7 && etd->samples[1] == 0x2A)
+               sanity_check = ((packet[3] & 0x1c) == 0x10);
        else
                sanity_check = ((packet[0] & 0x0c) == 0x04 &&
                                (packet[3] & 0x1c) == 0x10);
@@ -1116,6 +1123,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
  * Avatar AVIU-145A2       0x361f00        ?               clickpad
  * Fujitsu LIFEBOOK E544   0x470f00        d0, 12, 09      2 hw buttons
  * Fujitsu LIFEBOOK E554   0x570f01        40, 14, 0c      2 hw buttons
+ * Fujitsu T725            0x470f01        05, 12, 09      2 hw buttons
  * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
  * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
  * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*)
@@ -1167,7 +1175,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
        struct input_dev *dev = psmouse->dev;
        struct elantech_data *etd = psmouse->private;
        unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
-       unsigned int x_res = 0, y_res = 0;
+       unsigned int x_res = 31, y_res = 31;
 
        if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
                return -1;
@@ -1232,8 +1240,6 @@ static int elantech_set_input_params(struct psmouse *psmouse)
                /* For X to recognize me as touchpad. */
                input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
                input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
-               input_abs_set_res(dev, ABS_X, x_res);
-               input_abs_set_res(dev, ABS_Y, y_res);
                /*
                 * range of pressure and width is the same as v2,
                 * report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility.
@@ -1246,8 +1252,6 @@ static int elantech_set_input_params(struct psmouse *psmouse)
                input_mt_init_slots(dev, ETP_MAX_FINGERS, 0);
                input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
                input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
-               input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
-               input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
                input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2,
                                     ETP_PMAX_V2, 0, 0);
                /*
@@ -1259,6 +1263,13 @@ static int elantech_set_input_params(struct psmouse *psmouse)
                break;
        }
 
+       input_abs_set_res(dev, ABS_X, x_res);
+       input_abs_set_res(dev, ABS_Y, y_res);
+       if (etd->hw_version > 1) {
+               input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
+               input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
+       }
+
        etd->y_max = y_max;
        etd->width = width;
 
@@ -1648,6 +1659,16 @@ int elantech_init(struct psmouse *psmouse)
                     etd->capabilities[0], etd->capabilities[1],
                     etd->capabilities[2]);
 
+       if (etd->hw_version != 1) {
+               if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, etd->samples)) {
+                       psmouse_err(psmouse, "failed to query sample data\n");
+                       goto init_fail;
+               }
+               psmouse_info(psmouse,
+                            "Elan sample query result %02x, %02x, %02x\n",
+                            etd->samples[0], etd->samples[1], etd->samples[2]);
+       }
+
        if (elantech_set_absolute_mode(psmouse)) {
                psmouse_err(psmouse,
                            "failed to put touchpad into absolute mode.\n");
index f965d1569cc338059cdd540bad44ed927c6ddc3e..e1cbf409d9c8d0d4e7d21e13d57851ae6565b535 100644 (file)
@@ -129,6 +129,7 @@ struct elantech_data {
        unsigned char reg_26;
        unsigned char debug;
        unsigned char capabilities[3];
+       unsigned char samples[3];
        bool paritycheck;
        bool jumpy_cursor;
        bool reports_pressure;
index 3a32caf06bf1dae9b9fb678947bb9c7243fc25da..6025eb430c0a5010c908961ccf8897943fd3c945 100644 (file)
@@ -1484,12 +1484,12 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
        priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
 
        psmouse_info(psmouse,
-                    "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n",
+                    "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n",
                     SYN_ID_MODEL(priv->identity),
                     SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
                     priv->model_id,
                     priv->capabilities, priv->ext_cap, priv->ext_cap_0c,
-                    priv->board_id, priv->firmware_id);
+                    priv->ext_cap_10, priv->board_id, priv->firmware_id);
 
        set_input_params(psmouse, priv);
 
index b4d12e29abff72008125c2406b3808cf174e0f71..e36162b28c2aae268166c2e735e318b793b9dfa8 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/dmi.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/mt.h>
@@ -34,6 +35,7 @@ struct goodix_ts_data {
        int abs_y_max;
        unsigned int max_touch_num;
        unsigned int int_trigger_type;
+       bool rotated_screen;
 };
 
 #define GOODIX_MAX_HEIGHT              4096
@@ -60,6 +62,30 @@ static const unsigned long goodix_irq_flags[] = {
        IRQ_TYPE_LEVEL_HIGH,
 };
 
+/*
+ * Those tablets have their coordinates origin at the bottom right
+ * of the tablet, as if rotated 180 degrees
+ */
+static const struct dmi_system_id rotated_screen[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
+       {
+               .ident = "WinBook TW100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TW100")
+               }
+       },
+       {
+               .ident = "WinBook TW700",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TW700")
+               },
+       },
+#endif
+       {}
+};
+
 /**
  * goodix_i2c_read - read data from a register of the i2c slave device.
  *
@@ -129,6 +155,11 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
        int input_y = get_unaligned_le16(&coor_data[3]);
        int input_w = get_unaligned_le16(&coor_data[5]);
 
+       if (ts->rotated_screen) {
+               input_x = ts->abs_x_max - input_x;
+               input_y = ts->abs_y_max - input_y;
+       }
+
        input_mt_slot(ts->input_dev, id);
        input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
        input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
@@ -223,6 +254,11 @@ static void goodix_read_config(struct goodix_ts_data *ts)
                ts->abs_y_max = GOODIX_MAX_HEIGHT;
                ts->max_touch_num = GOODIX_MAX_CONTACTS;
        }
+
+       ts->rotated_screen = dmi_check_system(rotated_screen);
+       if (ts->rotated_screen)
+               dev_dbg(&ts->client->dev,
+                        "Applying '180 degrees rotated screen' quirk\n");
 }
 
 /**
index f2c6c352c55af2d3bb4dbf243516b19b9c62a65a..2c41107240dec274e5ec34724a882d87189f0103 100644 (file)
@@ -627,6 +627,9 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
                goto err_out;
        }
 
+       /* TSC-25 data sheet specifies a delay after the RESET command */
+       msleep(150);
+
        /* set coordinate output rate */
        buf[0] = buf[1] = 0xFF;
        ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
index a57e9b7498953bb9ebf947695caea46d73e2bfeb..658ee39e65696898422bcd9c825d8a49fbc37359 100644 (file)
@@ -76,8 +76,6 @@ LIST_HEAD(hpet_map);
  * Domain for untranslated devices - only allocated
  * if iommu=pt passed on kernel cmd line.
  */
-static struct protection_domain *pt_domain;
-
 static const struct iommu_ops amd_iommu_ops;
 
 static ATOMIC_NOTIFIER_HEAD(ppr_notifier);
@@ -96,7 +94,7 @@ struct iommu_dev_data {
        struct protection_domain *domain; /* Domain the device is bound to */
        u16 devid;                        /* PCI Device ID */
        bool iommu_v2;                    /* Device can make use of IOMMUv2 */
-       bool passthrough;                 /* Default for device is pt_domain */
+       bool passthrough;                 /* Device is identity mapped */
        struct {
                bool enabled;
                int qdep;
@@ -116,7 +114,6 @@ struct iommu_cmd {
 struct kmem_cache *amd_iommu_irq_cache;
 
 static void update_domain(struct protection_domain *domain);
-static int alloc_passthrough_domain(void);
 static int protection_domain_init(struct protection_domain *domain);
 
 /****************************************************************************
@@ -2167,15 +2164,17 @@ static int attach_device(struct device *dev,
        dev_data = get_dev_data(dev);
 
        if (domain->flags & PD_IOMMUV2_MASK) {
-               if (!dev_data->iommu_v2 || !dev_data->passthrough)
+               if (!dev_data->passthrough)
                        return -EINVAL;
 
-               if (pdev_iommuv2_enable(pdev) != 0)
-                       return -EINVAL;
+               if (dev_data->iommu_v2) {
+                       if (pdev_iommuv2_enable(pdev) != 0)
+                               return -EINVAL;
 
-               dev_data->ats.enabled = true;
-               dev_data->ats.qdep    = pci_ats_queue_depth(pdev);
-               dev_data->pri_tlp     = pci_pri_tlp_required(pdev);
+                       dev_data->ats.enabled = true;
+                       dev_data->ats.qdep    = pci_ats_queue_depth(pdev);
+                       dev_data->pri_tlp     = pci_pri_tlp_required(pdev);
+               }
        } else if (amd_iommu_iotlb_sup &&
                   pci_enable_ats(pdev, PAGE_SHIFT) == 0) {
                dev_data->ats.enabled = true;
@@ -2221,15 +2220,6 @@ static void __detach_device(struct iommu_dev_data *dev_data)
        do_detach(head);
 
        spin_unlock_irqrestore(&domain->lock, flags);
-
-       /*
-        * If we run in passthrough mode the device must be assigned to the
-        * passthrough domain if it is detached from any other domain.
-        * Make sure we can deassign from the pt_domain itself.
-        */
-       if (dev_data->passthrough &&
-           (dev_data->domain == NULL && domain != pt_domain))
-               __attach_device(dev_data, pt_domain);
 }
 
 /*
@@ -2249,7 +2239,7 @@ static void detach_device(struct device *dev)
        __detach_device(dev_data);
        write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
 
-       if (domain->flags & PD_IOMMUV2_MASK)
+       if (domain->flags & PD_IOMMUV2_MASK && dev_data->iommu_v2)
                pdev_iommuv2_disable(to_pci_dev(dev));
        else if (dev_data->ats.enabled)
                pci_disable_ats(to_pci_dev(dev));
@@ -2287,17 +2277,15 @@ static int amd_iommu_add_device(struct device *dev)
 
        BUG_ON(!dev_data);
 
-       if (dev_data->iommu_v2)
+       if (iommu_pass_through || dev_data->iommu_v2)
                iommu_request_dm_for_dev(dev);
 
        /* Domains are initialized for this device - have a look what we ended up with */
        domain = iommu_get_domain_for_dev(dev);
-       if (domain->type == IOMMU_DOMAIN_IDENTITY) {
+       if (domain->type == IOMMU_DOMAIN_IDENTITY)
                dev_data->passthrough = true;
-               dev->archdata.dma_ops = &nommu_dma_ops;
-       } else {
+       else
                dev->archdata.dma_ops = &amd_iommu_dma_ops;
-       }
 
 out:
        iommu_completion_wait(iommu);
@@ -2862,8 +2850,17 @@ int __init amd_iommu_init_api(void)
 
 int __init amd_iommu_init_dma_ops(void)
 {
+       swiotlb        = iommu_pass_through ? 1 : 0;
        iommu_detected = 1;
-       swiotlb = 0;
+
+       /*
+        * In case we don't initialize SWIOTLB (actually the common case
+        * when AMD IOMMU is enabled), make sure there are global
+        * dma_ops set as a fall-back for devices not handled by this
+        * driver (for example non-PCI devices).
+        */
+       if (!swiotlb)
+               dma_ops = &nommu_dma_ops;
 
        amd_iommu_stats_init();
 
@@ -2947,21 +2944,6 @@ out_err:
        return NULL;
 }
 
-static int alloc_passthrough_domain(void)
-{
-       if (pt_domain != NULL)
-               return 0;
-
-       /* allocate passthrough domain */
-       pt_domain = protection_domain_alloc();
-       if (!pt_domain)
-               return -ENOMEM;
-
-       pt_domain->mode = PAGE_MODE_NONE;
-
-       return 0;
-}
-
 static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
 {
        struct protection_domain *pdomain;
@@ -3222,33 +3204,6 @@ static const struct iommu_ops amd_iommu_ops = {
  *
  *****************************************************************************/
 
-int __init amd_iommu_init_passthrough(void)
-{
-       struct iommu_dev_data *dev_data;
-       struct pci_dev *dev = NULL;
-       int ret;
-
-       ret = alloc_passthrough_domain();
-       if (ret)
-               return ret;
-
-       for_each_pci_dev(dev) {
-               if (!check_device(&dev->dev))
-                       continue;
-
-               dev_data = get_dev_data(&dev->dev);
-               dev_data->passthrough = true;
-
-               attach_device(&dev->dev, pt_domain);
-       }
-
-       amd_iommu_stats_init();
-
-       pr_info("AMD-Vi: Initialized for Passthrough Mode\n");
-
-       return 0;
-}
-
 /* IOMMUv2 specific functions */
 int amd_iommu_register_ppr_notifier(struct notifier_block *nb)
 {
@@ -3363,7 +3318,12 @@ static int __flush_pasid(struct protection_domain *domain, int pasid,
                struct amd_iommu *iommu;
                int qdep;
 
-               BUG_ON(!dev_data->ats.enabled);
+               /*
+                  There might be non-IOMMUv2 capable devices in an IOMMUv2
+                * domain.
+                */
+               if (!dev_data->ats.enabled)
+                       continue;
 
                qdep  = dev_data->ats.qdep;
                iommu = amd_iommu_rlookup_table[dev_data->devid];
index dbda9ae68c5d70fff7926e39a2ef506b7165bf65..a24495eb4e26c5c596efa79c084b14c19fe5932c 100644 (file)
@@ -2026,14 +2026,6 @@ static bool detect_ivrs(void)
        return true;
 }
 
-static int amd_iommu_init_dma(void)
-{
-       if (iommu_pass_through)
-               return amd_iommu_init_passthrough();
-       else
-               return amd_iommu_init_dma_ops();
-}
-
 /****************************************************************************
  *
  * AMD IOMMU Initialization State Machine
@@ -2073,7 +2065,7 @@ static int __init state_next(void)
                init_state = ret ? IOMMU_INIT_ERROR : IOMMU_INTERRUPTS_EN;
                break;
        case IOMMU_INTERRUPTS_EN:
-               ret = amd_iommu_init_dma();
+               ret = amd_iommu_init_dma_ops();
                init_state = ret ? IOMMU_INIT_ERROR : IOMMU_DMA_OPS;
                break;
        case IOMMU_DMA_OPS:
index 3465faf1809e4cb1d6630e5cdc8f87cd4e405bd2..f7b875bb70d42138027f49ebde8150d27ce14cd2 100644 (file)
@@ -132,11 +132,19 @@ static struct device_state *get_device_state(u16 devid)
 
 static void free_device_state(struct device_state *dev_state)
 {
+       struct iommu_group *group;
+
        /*
         * First detach device from domain - No more PRI requests will arrive
         * from that device after it is unbound from the IOMMUv2 domain.
         */
-       iommu_detach_device(dev_state->domain, &dev_state->pdev->dev);
+       group = iommu_group_get(&dev_state->pdev->dev);
+       if (WARN_ON(!group))
+               return;
+
+       iommu_detach_group(dev_state->domain, group);
+
+       iommu_group_put(group);
 
        /* Everything is down now, free the IOMMUv2 domain */
        iommu_domain_free(dev_state->domain);
@@ -731,6 +739,7 @@ EXPORT_SYMBOL(amd_iommu_unbind_pasid);
 int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
 {
        struct device_state *dev_state;
+       struct iommu_group *group;
        unsigned long flags;
        int ret, tmp;
        u16 devid;
@@ -776,10 +785,16 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
        if (ret)
                goto out_free_domain;
 
-       ret = iommu_attach_device(dev_state->domain, &pdev->dev);
-       if (ret != 0)
+       group = iommu_group_get(&pdev->dev);
+       if (!group)
                goto out_free_domain;
 
+       ret = iommu_attach_group(dev_state->domain, group);
+       if (ret != 0)
+               goto out_drop_group;
+
+       iommu_group_put(group);
+
        spin_lock_irqsave(&state_lock, flags);
 
        if (__get_device_state(devid) != NULL) {
@@ -794,6 +809,9 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
 
        return 0;
 
+out_drop_group:
+       iommu_group_put(group);
+
 out_free_domain:
        iommu_domain_free(dev_state->domain);
 
index 8e9ec81ce4bbd85473d6d6a35e7c3567569187ee..da902baaa7946aac569b7ebe8a316c647dfd8187 100644 (file)
  * Stream table.
  *
  * Linear: Enough to cover 1 << IDR1.SIDSIZE entries
- * 2lvl: 8k L1 entries, 256 lazy entries per table (each table covers a PCI bus)
+ * 2lvl: 128k L1 entries,
+ *       256 lazy entries per table (each table covers a PCI bus)
  */
-#define STRTAB_L1_SZ_SHIFT             16
+#define STRTAB_L1_SZ_SHIFT             20
 #define STRTAB_SPLIT                   8
 
 #define STRTAB_L1_DESC_DWORDS          1
 #define ARM64_TCR_TG0_SHIFT            14
 #define ARM64_TCR_TG0_MASK             0x3UL
 #define CTXDESC_CD_0_TCR_IRGN0_SHIFT   8
-#define ARM64_TCR_IRGN0_SHIFT          24
+#define ARM64_TCR_IRGN0_SHIFT          8
 #define ARM64_TCR_IRGN0_MASK           0x3UL
 #define CTXDESC_CD_0_TCR_ORGN0_SHIFT   10
-#define ARM64_TCR_ORGN0_SHIFT          26
+#define ARM64_TCR_ORGN0_SHIFT          10
 #define ARM64_TCR_ORGN0_MASK           0x3UL
 #define CTXDESC_CD_0_TCR_SH0_SHIFT     12
 #define ARM64_TCR_SH0_SHIFT            12
@@ -542,6 +543,9 @@ struct arm_smmu_device {
 #define ARM_SMMU_FEAT_HYP              (1 << 12)
        u32                             features;
 
+#define ARM_SMMU_OPT_SKIP_PREFETCH     (1 << 0)
+       u32                             options;
+
        struct arm_smmu_cmdq            cmdq;
        struct arm_smmu_evtq            evtq;
        struct arm_smmu_priq            priq;
@@ -602,11 +606,35 @@ struct arm_smmu_domain {
 static DEFINE_SPINLOCK(arm_smmu_devices_lock);
 static LIST_HEAD(arm_smmu_devices);
 
+struct arm_smmu_option_prop {
+       u32 opt;
+       const char *prop;
+};
+
+static struct arm_smmu_option_prop arm_smmu_options[] = {
+       { ARM_SMMU_OPT_SKIP_PREFETCH, "hisilicon,broken-prefetch-cmd" },
+       { 0, NULL},
+};
+
 static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
 {
        return container_of(dom, struct arm_smmu_domain, domain);
 }
 
+static void parse_driver_options(struct arm_smmu_device *smmu)
+{
+       int i = 0;
+
+       do {
+               if (of_property_read_bool(smmu->dev->of_node,
+                                               arm_smmu_options[i].prop)) {
+                       smmu->options |= arm_smmu_options[i].opt;
+                       dev_notice(smmu->dev, "option %s\n",
+                               arm_smmu_options[i].prop);
+               }
+       } while (arm_smmu_options[++i].opt);
+}
+
 /* Low-level queue manipulation functions */
 static bool queue_full(struct arm_smmu_queue *q)
 {
@@ -1036,7 +1064,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
        arm_smmu_sync_ste_for_sid(smmu, sid);
 
        /* It's likely that we'll want to use the new STE soon */
-       arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd);
+       if (!(smmu->options & ARM_SMMU_OPT_SKIP_PREFETCH))
+               arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd);
 }
 
 static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent)
@@ -1064,7 +1093,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
                return 0;
 
        size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
-       strtab = &cfg->strtab[sid >> STRTAB_SPLIT << STRTAB_L1_DESC_DWORDS];
+       strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
 
        desc->span = STRTAB_SPLIT + 1;
        desc->l2ptr = dma_zalloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
@@ -2020,21 +2049,23 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
 {
        void *strtab;
        u64 reg;
-       u32 size;
+       u32 size, l1size;
        int ret;
        struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
 
        /* Calculate the L1 size, capped to the SIDSIZE */
        size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3);
        size = min(size, smmu->sid_bits - STRTAB_SPLIT);
-       if (size + STRTAB_SPLIT < smmu->sid_bits)
+       cfg->num_l1_ents = 1 << size;
+
+       size += STRTAB_SPLIT;
+       if (size < smmu->sid_bits)
                dev_warn(smmu->dev,
                         "2-level strtab only covers %u/%u bits of SID\n",
-                        size + STRTAB_SPLIT, smmu->sid_bits);
+                        size, smmu->sid_bits);
 
-       cfg->num_l1_ents = 1 << size;
-       size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
-       strtab = dma_zalloc_coherent(smmu->dev, size, &cfg->strtab_dma,
+       l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
+       strtab = dma_zalloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,
                                     GFP_KERNEL);
        if (!strtab) {
                dev_err(smmu->dev,
@@ -2055,8 +2086,7 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
        ret = arm_smmu_init_l1_strtab(smmu);
        if (ret)
                dma_free_coherent(smmu->dev,
-                                 cfg->num_l1_ents *
-                                 (STRTAB_L1_DESC_DWORDS << 3),
+                                 l1size,
                                  strtab,
                                  cfg->strtab_dma);
        return ret;
@@ -2573,6 +2603,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
        if (irq > 0)
                smmu->gerr_irq = irq;
 
+       parse_driver_options(smmu);
+
        /* Probe the h/w */
        ret = arm_smmu_device_probe(smmu);
        if (ret)
index a98a7b27aca1dec2cb2f53319df8a49abcf8e645..0649b94f59584ca5b885cd0ecad595a84af0d89d 100644 (file)
@@ -1830,8 +1830,9 @@ 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)
@@ -1851,8 +1852,10 @@ static void domain_exit(struct dmar_domain *domain)
 
        /* clear attached or cached domains */
        rcu_read_lock();
-       for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus)
-               iommu_detach_domain(domain, g_iommus[i]);
+       for_each_active_iommu(iommu, drhd)
+               if (domain_type_is_vm(domain) ||
+                   test_bit(iommu->seq_id, domain->iommu_bmp))
+                       iommu_detach_domain(domain, iommu);
        rcu_read_unlock();
 
        dma_free_pagelist(freelist);
index b7d54d428b5e55d1520d52e68b95202593cf4b53..ff4be0515a0dc7dbb206ae0a84968f922817101e 100644 (file)
@@ -538,7 +538,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index 8c91fd5eb6fdd4696f8b6d298eef8684525fc94e..375be509e95f5bd302da79446cb8867f8ecb8ec7 100644 (file)
@@ -524,9 +524,18 @@ gigaset_tty_open(struct tty_struct *tty)
        cs->hw.ser->tty = tty;
        atomic_set(&cs->hw.ser->refcnt, 1);
        init_completion(&cs->hw.ser->dead_cmp);
-
        tty->disc_data = cs;
 
+       /* Set the amount of data we're willing to receive per call
+        * from the hardware driver to half of the input buffer size
+        * to leave some reserve.
+        * Note: We don't do flow control towards the hardware driver.
+        * If more data is received than will fit into the input buffer,
+        * it will be dropped and an error will be logged. This should
+        * never happen as the device is slow and the buffer size ample.
+        */
+       tty->receive_room = RBUFSIZE/2;
+
        /* OK.. Initialization of the datastructures and the HW is done.. Now
         * startup system and notify the LL that we are ready to run
         */
@@ -597,28 +606,6 @@ static int gigaset_tty_hangup(struct tty_struct *tty)
        return 0;
 }
 
-/*
- * Read on the tty.
- * Unused, received data goes only to the Gigaset driver.
- */
-static ssize_t
-gigaset_tty_read(struct tty_struct *tty, struct file *file,
-                unsigned char __user *buf, size_t count)
-{
-       return -EAGAIN;
-}
-
-/*
- * Write on the tty.
- * Unused, transmit data comes only from the Gigaset driver.
- */
-static ssize_t
-gigaset_tty_write(struct tty_struct *tty, struct file *file,
-                 const unsigned char *buf, size_t count)
-{
-       return -EAGAIN;
-}
-
 /*
  * Ioctl on the tty.
  * Called in process context only.
@@ -752,8 +739,6 @@ static struct tty_ldisc_ops gigaset_ldisc = {
        .open           = gigaset_tty_open,
        .close          = gigaset_tty_close,
        .hangup         = gigaset_tty_hangup,
-       .read           = gigaset_tty_read,
-       .write          = gigaset_tty_write,
        .ioctl          = gigaset_tty_ioctl,
        .receive_buf    = gigaset_tty_receive,
        .write_wakeup   = gigaset_tty_wakeup,
index 1a57e88a38f7554ef3c09199090ce52575d041ef..cd35079c8c98b69469e1e64794b6a7345c382f3b 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/fcntl.h>
-#include <linux/init.h>
+#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
 
index b59727309072462fb3d0dc42935000d9570a7589..bfec3bdfe59847c8f3553e178a8b33a1c5a708fd 100644 (file)
@@ -259,7 +259,7 @@ config DM_CRYPT
          the ciphers you're going to use in the cryptoapi configuration.
 
          For further information on dm-crypt and userspace tools see:
-         <http://code.google.com/p/cryptsetup/wiki/DMCrypt>
+         <https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt>
 
          To compile this code as a module, choose M here: the module will
          be called dm-crypt.
index ed2346ddf4c9fb54dafeb92ae9c795a0584444e8..e51de52eeb94f71c9d6712a61d31e49f8e6f2f60 100644 (file)
@@ -494,7 +494,7 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap)
        bitmap_super_t *sb;
        unsigned long chunksize, daemon_sleep, write_behind;
 
-       bitmap->storage.sb_page = alloc_page(GFP_KERNEL);
+       bitmap->storage.sb_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
        if (bitmap->storage.sb_page == NULL)
                return -ENOMEM;
        bitmap->storage.sb_page->index = 0;
@@ -541,6 +541,7 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap)
        sb->state = cpu_to_le32(bitmap->flags);
        bitmap->events_cleared = bitmap->mddev->events;
        sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
+       bitmap->mddev->bitmap_info.nodes = 0;
 
        kunmap_atomic(sb);
 
@@ -558,6 +559,7 @@ static int bitmap_read_sb(struct bitmap *bitmap)
        unsigned long sectors_reserved = 0;
        int err = -EINVAL;
        struct page *sb_page;
+       loff_t offset = bitmap->mddev->bitmap_info.offset;
 
        if (!bitmap->storage.file && !bitmap->mddev->bitmap_info.offset) {
                chunksize = 128 * 1024 * 1024;
@@ -584,9 +586,9 @@ re_read:
                bm_blocks = ((bm_blocks+7) >> 3) + sizeof(bitmap_super_t);
                /* to 4k blocks */
                bm_blocks = DIV_ROUND_UP_SECTOR_T(bm_blocks, 4096);
-               bitmap->mddev->bitmap_info.offset += bitmap->cluster_slot * (bm_blocks << 3);
+               offset = bitmap->mddev->bitmap_info.offset + (bitmap->cluster_slot * (bm_blocks << 3));
                pr_info("%s:%d bm slot: %d offset: %llu\n", __func__, __LINE__,
-                       bitmap->cluster_slot, (unsigned long long)bitmap->mddev->bitmap_info.offset);
+                       bitmap->cluster_slot, offset);
        }
 
        if (bitmap->storage.file) {
@@ -597,7 +599,7 @@ re_read:
                                bitmap, bytes, sb_page);
        } else {
                err = read_sb_page(bitmap->mddev,
-                                  bitmap->mddev->bitmap_info.offset,
+                                  offset,
                                   sb_page,
                                   0, sizeof(bitmap_super_t));
        }
@@ -611,8 +613,16 @@ re_read:
        daemon_sleep = le32_to_cpu(sb->daemon_sleep) * HZ;
        write_behind = le32_to_cpu(sb->write_behind);
        sectors_reserved = le32_to_cpu(sb->sectors_reserved);
-       nodes = le32_to_cpu(sb->nodes);
-       strlcpy(bitmap->mddev->bitmap_info.cluster_name, sb->cluster_name, 64);
+       /* XXX: This is a hack to ensure that we don't use clustering
+        *  in case:
+        *      - dm-raid is in use and
+        *      - the nodes written in bitmap_sb is erroneous.
+        */
+       if (!bitmap->mddev->sync_super) {
+               nodes = le32_to_cpu(sb->nodes);
+               strlcpy(bitmap->mddev->bitmap_info.cluster_name,
+                               sb->cluster_name, 64);
+       }
 
        /* verify that the bitmap-specific fields are valid */
        if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
@@ -671,7 +681,7 @@ out:
        kunmap_atomic(sb);
        /* Assiging chunksize is required for "re_read" */
        bitmap->mddev->bitmap_info.chunksize = chunksize;
-       if (nodes && (bitmap->cluster_slot < 0)) {
+       if (err == 0 && nodes && (bitmap->cluster_slot < 0)) {
                err = md_setup_cluster(bitmap->mddev, nodes);
                if (err) {
                        pr_err("%s: Could not setup cluster service (%d)\n",
@@ -1866,10 +1876,6 @@ int bitmap_copy_from_slot(struct mddev *mddev, int slot,
        if (IS_ERR(bitmap))
                return PTR_ERR(bitmap);
 
-       rv = bitmap_read_sb(bitmap);
-       if (rv)
-               goto err;
-
        rv = bitmap_init_from_disk(bitmap, 0);
        if (rv)
                goto err;
index 32814371b8d304539a2eb1cfece077510b4ca394..aa1b41ca40f778dcb4e6c0e393ab4ee33d25d388 100644 (file)
@@ -1471,5 +1471,3 @@ module_exit(mq_exit);
 MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("mq cache policy");
-
-MODULE_ALIAS("dm-cache-default");
index b6f22651dd356e7e5b4d0bed4268f4ac9dd62772..200366c62231dd5f8f38f74284a42810c8603d19 100644 (file)
@@ -1686,7 +1686,7 @@ static struct dm_cache_policy *smq_create(dm_cblock_t cache_size,
 
        if (from_cblock(cache_size)) {
                mq->cache_hit_bits = alloc_bitset(from_cblock(cache_size));
-               if (!mq->cache_hit_bits && mq->cache_hit_bits) {
+               if (!mq->cache_hit_bits) {
                        DMERR("couldn't allocate cache hit bitset");
                        goto bad_cache_hit_bits;
                }
@@ -1789,3 +1789,5 @@ module_exit(smq_exit);
 MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("smq cache policy");
+
+MODULE_ALIAS("dm-cache-default");
index b680da5d7b93b5f68d65c0449df1b87b8e1b528b..1fe93cfea7d309a659d79fe2b953b5f2dbe7b466 100644 (file)
@@ -424,6 +424,7 @@ static void free_migration(struct dm_cache_migration *mg)
                wake_up(&cache->migration_wait);
 
        mempool_free(mg, cache->migration_pool);
+       wake_worker(cache);
 }
 
 static int prealloc_data_structs(struct cache *cache, struct prealloc *p)
@@ -1966,6 +1967,7 @@ static void process_deferred_bios(struct cache *cache)
                 * this bio might require one, we pause until there are some
                 * prepared mappings to process.
                 */
+               prealloc_used = true;
                if (prealloc_data_structs(cache, &structs)) {
                        spin_lock_irqsave(&cache->lock, flags);
                        bio_list_merge(&cache->deferred_bios, &bios);
@@ -1981,7 +1983,6 @@ static void process_deferred_bios(struct cache *cache)
                        process_discard_bio(cache, &structs, bio);
                else
                        process_bio(cache, &structs, bio);
-               prealloc_used = true;
        }
 
        if (prealloc_used)
@@ -2010,6 +2011,7 @@ static void process_deferred_cells(struct cache *cache)
                 * this bio might require one, we pause until there are some
                 * prepared mappings to process.
                 */
+               prealloc_used = true;
                if (prealloc_data_structs(cache, &structs)) {
                        spin_lock_irqsave(&cache->lock, flags);
                        list_splice(&cells, &cache->deferred_cells);
@@ -2018,7 +2020,6 @@ static void process_deferred_cells(struct cache *cache)
                }
 
                process_cell(cache, &structs, cell);
-               prealloc_used = true;
        }
 
        if (prealloc_used)
@@ -2080,6 +2081,7 @@ static void writeback_some_dirty_blocks(struct cache *cache)
                if (policy_writeback_work(cache->policy, &oblock, &cblock, busy))
                        break; /* no work to do */
 
+               prealloc_used = true;
                if (prealloc_data_structs(cache, &structs) ||
                    get_cell(cache, oblock, &structs, &old_ocell)) {
                        policy_set_dirty(cache->policy, oblock);
@@ -2087,7 +2089,6 @@ static void writeback_some_dirty_blocks(struct cache *cache)
                }
 
                writeback(cache, &structs, oblock, cblock, old_ocell);
-               prealloc_used = true;
        }
 
        if (prealloc_used)
index 48dfe3c4d6aa7968bbc1986eafcb9e965fe55950..6ba47cfb1443748ccf092819a6a5ef160bb856fd 100644 (file)
@@ -1293,8 +1293,8 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd)
                return r;
 
        disk_super = dm_block_data(copy);
-       dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->data_mapping_root));
-       dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->device_details_root));
+       dm_btree_del(&pmd->info, le64_to_cpu(disk_super->data_mapping_root));
+       dm_btree_del(&pmd->details_info, le64_to_cpu(disk_super->device_details_root));
        dm_sm_dec_block(pmd->metadata_sm, held_root);
 
        return dm_tm_unlock(pmd->tm, copy);
index 1c50c580215c84d97cdb7b1de07c3b9fe6a66f63..d2bbe8cc1e9786b66af798df9d8666d3fb96223c 100644 (file)
@@ -666,16 +666,21 @@ static void requeue_io(struct thin_c *tc)
        requeue_deferred_cells(tc);
 }
 
-static void error_retry_list(struct pool *pool)
+static void error_retry_list_with_code(struct pool *pool, int error)
 {
        struct thin_c *tc;
 
        rcu_read_lock();
        list_for_each_entry_rcu(tc, &pool->active_thins, list)
-               error_thin_bio_list(tc, &tc->retry_on_resume_list, -EIO);
+               error_thin_bio_list(tc, &tc->retry_on_resume_list, error);
        rcu_read_unlock();
 }
 
+static void error_retry_list(struct pool *pool)
+{
+       return error_retry_list_with_code(pool, -EIO);
+}
+
 /*
  * This section of code contains the logic for processing a thin device's IO.
  * Much of the code depends on pool object resources (lists, workqueues, etc)
@@ -2297,7 +2302,7 @@ static void do_no_space_timeout(struct work_struct *ws)
        if (get_pool_mode(pool) == PM_OUT_OF_DATA_SPACE && !pool->pf.error_if_no_space) {
                pool->pf.error_if_no_space = true;
                notify_of_pool_mode_change_to_oods(pool);
-               error_retry_list(pool);
+               error_retry_list_with_code(pool, -ENOSPC);
        }
 }
 
index ab37ae114e943c20c161f88b8c2a739206bfafab..0d7ab20c58dffc40d5c56c9427b7dd7f090c8bd3 100644 (file)
@@ -1729,7 +1729,8 @@ static int dm_merge_bvec(struct request_queue *q,
        struct mapped_device *md = q->queuedata;
        struct dm_table *map = dm_get_live_table_fast(md);
        struct dm_target *ti;
-       sector_t max_sectors, max_size = 0;
+       sector_t max_sectors;
+       int max_size = 0;
 
        if (unlikely(!map))
                goto out;
@@ -1742,18 +1743,10 @@ static int dm_merge_bvec(struct request_queue *q,
         * Find maximum amount of I/O that won't need splitting
         */
        max_sectors = min(max_io_len(bvm->bi_sector, ti),
-                         (sector_t) queue_max_sectors(q));
+                         (sector_t) BIO_MAX_SECTORS);
        max_size = (max_sectors << SECTOR_SHIFT) - bvm->bi_size;
-
-       /*
-        * FIXME: this stop-gap fix _must_ be cleaned up (by passing a sector_t
-        * to the targets' merge function since it holds sectors not bytes).
-        * Just doing this as an interim fix for stable@ because the more
-        * comprehensive cleanup of switching to sector_t will impact every
-        * DM target that implements a ->merge hook.
-        */
-       if (max_size > INT_MAX)
-               max_size = INT_MAX;
+       if (max_size < 0)
+               max_size = 0;
 
        /*
         * merge_bvec_fn() returns number of bytes
@@ -1761,13 +1754,13 @@ static int dm_merge_bvec(struct request_queue *q,
         * max is precomputed maximal io size
         */
        if (max_size && ti->type->merge)
-               max_size = ti->type->merge(ti, bvm, biovec, (int) max_size);
+               max_size = ti->type->merge(ti, bvm, biovec, max_size);
        /*
         * If the target doesn't support merge method and some of the devices
-        * provided their merge_bvec method (we know this by looking for the
-        * max_hw_sectors that dm_set_device_limits may set), then we can't
-        * allow bios with multiple vector entries.  So always set max_size
-        * to 0, and the code below allows just one page.
+        * provided their merge_bvec method (we know this by looking at
+        * queue_max_hw_sectors), then we can't allow bios with multiple vector
+        * entries.  So always set max_size to 0, and the code below allows
+        * just one page.
         */
        else if (queue_max_hw_sectors(q) <= PAGE_SIZE >> 9)
                max_size = 0;
index fcfc4b9b26728029e59023ae3762d271b8f7a676..0072190515e0f6edca1e09718dae5102b3e7d274 100644 (file)
@@ -44,6 +44,7 @@ struct resync_info {
 
 /* md_cluster_info flags */
 #define                MD_CLUSTER_WAITING_FOR_NEWDISK          1
+#define                MD_CLUSTER_SUSPEND_READ_BALANCING       2
 
 
 struct md_cluster_info {
@@ -275,6 +276,9 @@ clear_bit:
 
 static void recover_prep(void *arg)
 {
+       struct mddev *mddev = arg;
+       struct md_cluster_info *cinfo = mddev->cluster_info;
+       set_bit(MD_CLUSTER_SUSPEND_READ_BALANCING, &cinfo->state);
 }
 
 static void recover_slot(void *arg, struct dlm_slot *slot)
@@ -307,6 +311,7 @@ static void recover_done(void *arg, struct dlm_slot *slots,
 
        cinfo->slot_number = our_slot;
        complete(&cinfo->completion);
+       clear_bit(MD_CLUSTER_SUSPEND_READ_BALANCING, &cinfo->state);
 }
 
 static const struct dlm_lockspace_ops md_ls_ops = {
@@ -816,12 +821,17 @@ static void resync_finish(struct mddev *mddev)
        resync_send(mddev, RESYNCING, 0, 0);
 }
 
-static int area_resyncing(struct mddev *mddev, sector_t lo, sector_t hi)
+static int area_resyncing(struct mddev *mddev, int direction,
+               sector_t lo, sector_t hi)
 {
        struct md_cluster_info *cinfo = mddev->cluster_info;
        int ret = 0;
        struct suspend_info *s;
 
+       if ((direction == READ) &&
+               test_bit(MD_CLUSTER_SUSPEND_READ_BALANCING, &cinfo->state))
+               return 1;
+
        spin_lock_irq(&cinfo->suspend_lock);
        if (list_empty(&cinfo->suspend_list))
                goto out;
index 6817ee00e053d7d7e74b734185414c0cb3b18a38..00defe2badbc7952ec7d4cf358ad0408a2460b7f 100644 (file)
@@ -18,7 +18,7 @@ struct md_cluster_operations {
        int (*metadata_update_start)(struct mddev *mddev);
        int (*metadata_update_finish)(struct mddev *mddev);
        int (*metadata_update_cancel)(struct mddev *mddev);
-       int (*area_resyncing)(struct mddev *mddev, sector_t lo, sector_t hi);
+       int (*area_resyncing)(struct mddev *mddev, int direction, sector_t lo, sector_t hi);
        int (*add_new_disk_start)(struct mddev *mddev, struct md_rdev *rdev);
        int (*add_new_disk_finish)(struct mddev *mddev);
        int (*new_disk_ack)(struct mddev *mddev, bool ack);
index d429c30cd51471c26cb1c07cb3e6a413106133d4..e25f00f0138a7b4d82a5ae4f6fc7e1b6f0bb1b30 100644 (file)
@@ -5382,6 +5382,8 @@ static void __md_stop(struct mddev *mddev)
 {
        struct md_personality *pers = mddev->pers;
        mddev_detach(mddev);
+       /* Ensure ->event_work is done */
+       flush_workqueue(md_misc_wq);
        spin_lock(&mddev->lock);
        mddev->ready = 0;
        mddev->pers = NULL;
@@ -5757,7 +5759,7 @@ static int get_bitmap_file(struct mddev *mddev, void __user * arg)
        char *ptr;
        int err;
 
-       file = kmalloc(sizeof(*file), GFP_NOIO);
+       file = kzalloc(sizeof(*file), GFP_NOIO);
        if (!file)
                return -ENOMEM;
 
@@ -7437,7 +7439,7 @@ int md_setup_cluster(struct mddev *mddev, int nodes)
        err = request_module("md-cluster");
        if (err) {
                pr_err("md-cluster module not found.\n");
-               return err;
+               return -ENOENT;
        }
 
        spin_lock(&pers_lock);
index bf2b80d5c4707a64210b5e57deb785069dc7d921..8731b6ea026bd9b8cfbe2a21bbc06366e509181c 100644 (file)
@@ -138,4 +138,10 @@ int lower_bound(struct btree_node *n, uint64_t key);
 
 extern struct dm_block_validator btree_node_validator;
 
+/*
+ * Value type for upper levels of multi-level btrees.
+ */
+extern void init_le64_type(struct dm_transaction_manager *tm,
+                          struct dm_btree_value_type *vt);
+
 #endif /* DM_BTREE_INTERNAL_H */
index 9836c0ae897c33c4e227bca77cc95026c193f73c..4222f774cf369b1eb1b031bd652854c573b224af 100644 (file)
@@ -544,14 +544,6 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
        return r;
 }
 
-static struct dm_btree_value_type le64_type = {
-       .context = NULL,
-       .size = sizeof(__le64),
-       .inc = NULL,
-       .dec = NULL,
-       .equal = NULL
-};
-
 int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
                    uint64_t *keys, dm_block_t *new_root)
 {
@@ -559,12 +551,14 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
        int index = 0, r = 0;
        struct shadow_spine spine;
        struct btree_node *n;
+       struct dm_btree_value_type le64_vt;
 
+       init_le64_type(info->tm, &le64_vt);
        init_shadow_spine(&spine, info);
        for (level = 0; level < info->levels; level++) {
                r = remove_raw(&spine, info,
                               (level == last_level ?
-                               &info->value_type : &le64_type),
+                               &info->value_type : &le64_vt),
                               root, keys[level], (unsigned *)&index);
                if (r < 0)
                        break;
@@ -654,11 +648,13 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root,
        int index = 0, r = 0;
        struct shadow_spine spine;
        struct btree_node *n;
+       struct dm_btree_value_type le64_vt;
        uint64_t k;
 
+       init_le64_type(info->tm, &le64_vt);
        init_shadow_spine(&spine, info);
        for (level = 0; level < last_level; level++) {
-               r = remove_raw(&spine, info, &le64_type,
+               r = remove_raw(&spine, info, &le64_vt,
                               root, keys[level], (unsigned *) &index);
                if (r < 0)
                        goto out;
@@ -689,6 +685,7 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root,
                                             value_ptr(n, index));
 
                delete_at(n, index);
+               keys[last_level] = k + 1ull;
 
        } else
                r = -ENODATA;
index 1b5e13ec7f96a670ed7a9b5b472a5d2ee95a7dff..0dee514ba4c5f9e8d34d16e9d239ef333395c7d4 100644 (file)
@@ -249,3 +249,40 @@ int shadow_root(struct shadow_spine *s)
 {
        return s->root;
 }
+
+static void le64_inc(void *context, const void *value_le)
+{
+       struct dm_transaction_manager *tm = context;
+       __le64 v_le;
+
+       memcpy(&v_le, value_le, sizeof(v_le));
+       dm_tm_inc(tm, le64_to_cpu(v_le));
+}
+
+static void le64_dec(void *context, const void *value_le)
+{
+       struct dm_transaction_manager *tm = context;
+       __le64 v_le;
+
+       memcpy(&v_le, value_le, sizeof(v_le));
+       dm_tm_dec(tm, le64_to_cpu(v_le));
+}
+
+static int le64_equal(void *context, const void *value1_le, const void *value2_le)
+{
+       __le64 v1_le, v2_le;
+
+       memcpy(&v1_le, value1_le, sizeof(v1_le));
+       memcpy(&v2_le, value2_le, sizeof(v2_le));
+       return v1_le == v2_le;
+}
+
+void init_le64_type(struct dm_transaction_manager *tm,
+                   struct dm_btree_value_type *vt)
+{
+       vt->context = tm;
+       vt->size = sizeof(__le64);
+       vt->inc = le64_inc;
+       vt->dec = le64_dec;
+       vt->equal = le64_equal;
+}
index fdd3793e22f957ef08db71f897607c68ce6eb6a3..c7726cebc4950c24cb6f6f2b7cacfa6465bddeb6 100644 (file)
@@ -667,12 +667,7 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
        struct btree_node *n;
        struct dm_btree_value_type le64_type;
 
-       le64_type.context = NULL;
-       le64_type.size = sizeof(__le64);
-       le64_type.inc = NULL;
-       le64_type.dec = NULL;
-       le64_type.equal = NULL;
-
+       init_le64_type(info->tm, &le64_type);
        init_shadow_spine(&spine, info);
 
        for (level = 0; level < (info->levels - 1); level++) {
index f80f1af61ce70bce15a72d242d87c1c34da49a79..967a4ed73929ff44a38d9475c5e362fc2914c758 100644 (file)
@@ -336,7 +336,7 @@ static void raid1_end_read_request(struct bio *bio, int error)
                spin_lock_irqsave(&conf->device_lock, flags);
                if (r1_bio->mddev->degraded == conf->raid_disks ||
                    (r1_bio->mddev->degraded == conf->raid_disks-1 &&
-                    !test_bit(Faulty, &conf->mirrors[mirror].rdev->flags)))
+                    test_bit(In_sync, &conf->mirrors[mirror].rdev->flags)))
                        uptodate = 1;
                spin_unlock_irqrestore(&conf->device_lock, flags);
        }
@@ -541,7 +541,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
 
        if ((conf->mddev->recovery_cp < this_sector + sectors) ||
            (mddev_is_clustered(conf->mddev) &&
-           md_cluster_ops->area_resyncing(conf->mddev, this_sector,
+           md_cluster_ops->area_resyncing(conf->mddev, READ, this_sector,
                    this_sector + sectors)))
                choose_first = 1;
        else
@@ -1111,7 +1111,8 @@ static void make_request(struct mddev *mddev, struct bio * bio)
            ((bio_end_sector(bio) > mddev->suspend_lo &&
            bio->bi_iter.bi_sector < mddev->suspend_hi) ||
            (mddev_is_clustered(mddev) &&
-            md_cluster_ops->area_resyncing(mddev, bio->bi_iter.bi_sector, bio_end_sector(bio))))) {
+            md_cluster_ops->area_resyncing(mddev, WRITE,
+                    bio->bi_iter.bi_sector, bio_end_sector(bio))))) {
                /* As the suspend_* range is controlled by
                 * userspace, we want an interruptible
                 * wait.
@@ -1124,7 +1125,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
                        if (bio_end_sector(bio) <= mddev->suspend_lo ||
                            bio->bi_iter.bi_sector >= mddev->suspend_hi ||
                            (mddev_is_clustered(mddev) &&
-                            !md_cluster_ops->area_resyncing(mddev,
+                            !md_cluster_ops->area_resyncing(mddev, WRITE,
                                     bio->bi_iter.bi_sector, bio_end_sector(bio))))
                                break;
                        schedule();
@@ -1475,6 +1476,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
 {
        char b[BDEVNAME_SIZE];
        struct r1conf *conf = mddev->private;
+       unsigned long flags;
 
        /*
         * If it is not operational, then we have already marked it as dead
@@ -1494,14 +1496,13 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
                return;
        }
        set_bit(Blocked, &rdev->flags);
+       spin_lock_irqsave(&conf->device_lock, flags);
        if (test_and_clear_bit(In_sync, &rdev->flags)) {
-               unsigned long flags;
-               spin_lock_irqsave(&conf->device_lock, flags);
                mddev->degraded++;
                set_bit(Faulty, &rdev->flags);
-               spin_unlock_irqrestore(&conf->device_lock, flags);
        } else
                set_bit(Faulty, &rdev->flags);
+       spin_unlock_irqrestore(&conf->device_lock, flags);
        /*
         * if recovery is running, make sure it aborts.
         */
@@ -1567,7 +1568,10 @@ static int raid1_spare_active(struct mddev *mddev)
         * Find all failed disks within the RAID1 configuration
         * and mark them readable.
         * Called under mddev lock, so rcu protection not needed.
+        * device_lock used to avoid races with raid1_end_read_request
+        * which expects 'In_sync' flags and ->degraded to be consistent.
         */
+       spin_lock_irqsave(&conf->device_lock, flags);
        for (i = 0; i < conf->raid_disks; i++) {
                struct md_rdev *rdev = conf->mirrors[i].rdev;
                struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev;
@@ -1598,7 +1602,6 @@ static int raid1_spare_active(struct mddev *mddev)
                        sysfs_notify_dirent_safe(rdev->sysfs_state);
                }
        }
-       spin_lock_irqsave(&conf->device_lock, flags);
        mddev->degraded -= count;
        spin_unlock_irqrestore(&conf->device_lock, flags);
 
index 940f2f3654617918d8eef951262c3ca120ab83ce..38c58e19cfce3d7bdea554b26474080a88e02cca 100644 (file)
@@ -3556,6 +3556,7 @@ static struct r10conf *setup_conf(struct mddev *mddev)
                        /* far_copies must be 1 */
                        conf->prev.stride = conf->dev_sectors;
        }
+       conf->reshape_safe = conf->reshape_progress;
        spin_lock_init(&conf->device_lock);
        INIT_LIST_HEAD(&conf->retry_list);
 
@@ -3760,7 +3761,6 @@ static int run(struct mddev *mddev)
                }
                conf->offset_diff = min_offset_diff;
 
-               conf->reshape_safe = conf->reshape_progress;
                clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
                clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
                set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
@@ -4103,6 +4103,7 @@ static int raid10_start_reshape(struct mddev *mddev)
                conf->reshape_progress = size;
        } else
                conf->reshape_progress = 0;
+       conf->reshape_safe = conf->reshape_progress;
        spin_unlock_irq(&conf->device_lock);
 
        if (mddev->delta_disks && mddev->bitmap) {
@@ -4170,6 +4171,7 @@ abort:
                rdev->new_data_offset = rdev->data_offset;
        smp_wmb();
        conf->reshape_progress = MaxSector;
+       conf->reshape_safe = MaxSector;
        mddev->reshape_position = MaxSector;
        spin_unlock_irq(&conf->device_lock);
        return ret;
@@ -4524,6 +4526,7 @@ static void end_reshape(struct r10conf *conf)
        md_finish_reshape(conf->mddev);
        smp_wmb();
        conf->reshape_progress = MaxSector;
+       conf->reshape_safe = MaxSector;
        spin_unlock_irq(&conf->device_lock);
 
        /* read-ahead size must cover two whole stripes, which is
index 59e44e99eef3bacd4703fd6883513688f7c58b09..f757023fc4580680bfdd6e178f93acb62cb1f31e 100644 (file)
@@ -2162,6 +2162,9 @@ static int resize_stripes(struct r5conf *conf, int newsize)
        if (!sc)
                return -ENOMEM;
 
+       /* Need to ensure auto-resizing doesn't interfere */
+       mutex_lock(&conf->cache_size_mutex);
+
        for (i = conf->max_nr_stripes; i; i--) {
                nsh = alloc_stripe(sc, GFP_KERNEL);
                if (!nsh)
@@ -2178,6 +2181,7 @@ static int resize_stripes(struct r5conf *conf, int newsize)
                        kmem_cache_free(sc, nsh);
                }
                kmem_cache_destroy(sc);
+               mutex_unlock(&conf->cache_size_mutex);
                return -ENOMEM;
        }
        /* Step 2 - Must use GFP_NOIO now.
@@ -2224,6 +2228,7 @@ static int resize_stripes(struct r5conf *conf, int newsize)
        } else
                err = -ENOMEM;
 
+       mutex_unlock(&conf->cache_size_mutex);
        /* Step 4, return new stripes to service */
        while(!list_empty(&newstripes)) {
                nsh = list_entry(newstripes.next, struct stripe_head, lru);
@@ -2251,7 +2256,7 @@ static int resize_stripes(struct r5conf *conf, int newsize)
 static int drop_one_stripe(struct r5conf *conf)
 {
        struct stripe_head *sh;
-       int hash = (conf->max_nr_stripes - 1) % NR_STRIPE_HASH_LOCKS;
+       int hash = (conf->max_nr_stripes - 1) & STRIPE_HASH_LOCKS_MASK;
 
        spin_lock_irq(conf->hash_locks + hash);
        sh = get_free_stripe(conf, hash);
@@ -4061,8 +4066,10 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
                                 &first_bad, &bad_sectors))
                        set_bit(R5_ReadRepl, &dev->flags);
                else {
-                       if (rdev)
+                       if (rdev && !test_bit(Faulty, &rdev->flags))
                                set_bit(R5_NeedReplace, &dev->flags);
+                       else
+                               clear_bit(R5_NeedReplace, &dev->flags);
                        rdev = rcu_dereference(conf->disks[i].rdev);
                        clear_bit(R5_ReadRepl, &dev->flags);
                }
@@ -5857,12 +5864,14 @@ static void raid5d(struct md_thread *thread)
        pr_debug("%d stripes handled\n", handled);
 
        spin_unlock_irq(&conf->device_lock);
-       if (test_and_clear_bit(R5_ALLOC_MORE, &conf->cache_state)) {
+       if (test_and_clear_bit(R5_ALLOC_MORE, &conf->cache_state) &&
+           mutex_trylock(&conf->cache_size_mutex)) {
                grow_one_stripe(conf, __GFP_NOWARN);
                /* Set flag even if allocation failed.  This helps
                 * slow down allocation requests when mem is short
                 */
                set_bit(R5_DID_ALLOC, &conf->cache_state);
+               mutex_unlock(&conf->cache_size_mutex);
        }
 
        async_tx_issue_pending_all();
@@ -5894,18 +5903,22 @@ raid5_set_cache_size(struct mddev *mddev, int size)
                return -EINVAL;
 
        conf->min_nr_stripes = size;
+       mutex_lock(&conf->cache_size_mutex);
        while (size < conf->max_nr_stripes &&
               drop_one_stripe(conf))
                ;
+       mutex_unlock(&conf->cache_size_mutex);
 
 
        err = md_allow_write(mddev);
        if (err)
                return err;
 
+       mutex_lock(&conf->cache_size_mutex);
        while (size > conf->max_nr_stripes)
                if (!grow_one_stripe(conf, GFP_KERNEL))
                        break;
+       mutex_unlock(&conf->cache_size_mutex);
 
        return 0;
 }
@@ -6371,11 +6384,19 @@ static unsigned long raid5_cache_scan(struct shrinker *shrink,
                                      struct shrink_control *sc)
 {
        struct r5conf *conf = container_of(shrink, struct r5conf, shrinker);
-       int ret = 0;
-       while (ret < sc->nr_to_scan) {
-               if (drop_one_stripe(conf) == 0)
-                       return SHRINK_STOP;
-               ret++;
+       unsigned long ret = SHRINK_STOP;
+
+       if (mutex_trylock(&conf->cache_size_mutex)) {
+               ret= 0;
+               while (ret < sc->nr_to_scan &&
+                      conf->max_nr_stripes > conf->min_nr_stripes) {
+                       if (drop_one_stripe(conf) == 0) {
+                               ret = SHRINK_STOP;
+                               break;
+                       }
+                       ret++;
+               }
+               mutex_unlock(&conf->cache_size_mutex);
        }
        return ret;
 }
@@ -6444,6 +6465,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
                goto abort;
        spin_lock_init(&conf->device_lock);
        seqcount_init(&conf->gen_lock);
+       mutex_init(&conf->cache_size_mutex);
        init_waitqueue_head(&conf->wait_for_quiescent);
        for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++) {
                init_waitqueue_head(&conf->wait_for_stripe[i]);
index 02c3bf8fbfe7aa1b0a1c568605393dc3769c6b18..d05144278690ca9b8cb4ad933d6d23dc36b9b0f8 100644 (file)
@@ -482,7 +482,8 @@ struct r5conf {
         */
        int                     active_name;
        char                    cache_name[2][32];
-       struct kmem_cache               *slab_cache; /* for allocating stripes */
+       struct kmem_cache       *slab_cache; /* for allocating stripes */
+       struct mutex            cache_size_mutex; /* Protect changes to cache size */
 
        int                     seq_flush, seq_write;
        int                     quiesce;
index 4cb365d4ffdcc9c4e12cde82f46d411cb86c7a13..8b95eefb610b4097787a7363c6e43b94ce260efb 100644 (file)
@@ -38,6 +38,8 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/fb.h>
@@ -1171,6 +1173,13 @@ static int ivtvfb_init_card(struct ivtv *itv)
 {
        int rc;
 
+#ifdef CONFIG_X86_64
+       if (pat_enabled()) {
+               pr_warn("ivtvfb needs PAT disabled, boot with nopat kernel parameter\n");
+               return -ENODEV;
+       }
+#endif
+
        if (itv->osd_info) {
                IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
                return -EBUSY;
@@ -1265,12 +1274,6 @@ static int __init ivtvfb_init(void)
        int registered = 0;
        int err;
 
-#ifdef CONFIG_X86_64
-       if (WARN(pat_enabled(),
-                "ivtvfb needs PAT disabled, boot with nopat kernel parameter\n")) {
-               return -ENODEV;
-       }
-#endif
 
        if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
                printk(KERN_ERR "ivtvfb:  ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
index 3a27a84ad3ec376a2543c1ac9568c30e5d7c131b..9426276dbe1402b1445dd7b84da6d7fca38893a6 100644 (file)
@@ -2245,6 +2245,9 @@ void omap3_gpmc_save_context(void)
 {
        int i;
 
+       if (!gpmc_base)
+               return;
+
        gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
        gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
        gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
@@ -2277,6 +2280,9 @@ void omap3_gpmc_restore_context(void)
 {
        int i;
 
+       if (!gpmc_base)
+               return;
+
        gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
        gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
        gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
index 379a420245eacdb3c17e34571ab738258ea5c44a..0f0cad8dcaedd7ec100b272da907b1360d8c720c 100644 (file)
@@ -115,7 +115,7 @@ config MFD_CROS_EC_I2C
 
 config MFD_CROS_EC_SPI
        tristate "ChromeOS Embedded Controller (SPI)"
-       depends on MFD_CROS_EC && CROS_EC_PROTO && SPI && OF
+       depends on MFD_CROS_EC && CROS_EC_PROTO && SPI
 
        ---help---
          If you say Y here, you get support for talking to the ChromeOS EC
index bebf58a06a6b2932d57798c0b5b81a31a12e9b7a..a72ddb2950784cf044fbfb5156ebd68866bbea48 100644 (file)
@@ -651,7 +651,7 @@ static int arizona_runtime_suspend(struct device *dev)
 
                arizona->has_fully_powered_off = true;
 
-               disable_irq(arizona->irq);
+               disable_irq_nosync(arizona->irq);
                arizona_enable_reset(arizona);
                regulator_bulk_disable(arizona->num_core_supplies,
                                       arizona->core_supplies);
@@ -1141,10 +1141,6 @@ int arizona_dev_init(struct arizona *arizona)
                             arizona->pdata.gpio_defaults[i]);
        }
 
-       pm_runtime_set_autosuspend_delay(arizona->dev, 100);
-       pm_runtime_use_autosuspend(arizona->dev);
-       pm_runtime_enable(arizona->dev);
-
        /* Chip default */
        if (!arizona->pdata.clk32k_src)
                arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2;
@@ -1245,11 +1241,17 @@ int arizona_dev_init(struct arizona *arizona)
                                           arizona->pdata.spk_fmt[i]);
        }
 
+       pm_runtime_set_active(arizona->dev);
+       pm_runtime_enable(arizona->dev);
+
        /* Set up for interrupts */
        ret = arizona_irq_init(arizona);
        if (ret != 0)
                goto err_reset;
 
+       pm_runtime_set_autosuspend_delay(arizona->dev, 100);
+       pm_runtime_use_autosuspend(arizona->dev);
+
        arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error",
                            arizona_clkgen_err, arizona);
        arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked",
@@ -1278,10 +1280,6 @@ int arizona_dev_init(struct arizona *arizona)
                goto err_irq;
        }
 
-#ifdef CONFIG_PM
-       regulator_disable(arizona->dcvdd);
-#endif
-
        return 0;
 
 err_irq:
index 2d3db81be0990a1b88109aa7614f74f201930204..6ded3dc36644a31a0bd4775f36df72f1c00a7e0d 100644 (file)
@@ -438,9 +438,6 @@ static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
 {
        struct at24_data *at24;
 
-       if (unlikely(off >= attr->size))
-               return -EFBIG;
-
        at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
        return at24_write(at24, buf, off, count);
 }
index 8eb0a9500a90626b5605025309b1abf53e2ee7cb..e9513d651cd36b611920a2f6410c905b344fbf13 100644 (file)
@@ -682,7 +682,7 @@ int mei_register(struct mei_device *dev, struct device *parent)
        /* Fill in the data structures */
        devno = MKDEV(MAJOR(mei_devt), dev->minor);
        cdev_init(&dev->cdev, &mei_fops);
-       dev->cdev.owner = mei_fops.owner;
+       dev->cdev.owner = parent->driver->owner;
 
        /* Add the device */
        ret = cdev_add(&dev->cdev, devno, 1);
index 41e3bdb100611ab2f20836d0f8d7e3a16d9b068a..6dfdae3452d609fd07c82cce24f933771a093a70 100644 (file)
@@ -357,7 +357,7 @@ static void scif_p2p_freesg(struct scatterlist *sg)
 }
 
 static struct scatterlist *
-scif_p2p_setsg(void __iomem *va, int page_size, int page_cnt)
+scif_p2p_setsg(phys_addr_t pa, int page_size, int page_cnt)
 {
        struct scatterlist *sg;
        struct page *page;
@@ -368,16 +368,11 @@ scif_p2p_setsg(void __iomem *va, int page_size, int page_cnt)
                return NULL;
        sg_init_table(sg, page_cnt);
        for (i = 0; i < page_cnt; i++) {
-               page = vmalloc_to_page((void __force *)va);
-               if (!page)
-                       goto p2p_sg_err;
+               page = pfn_to_page(pa >> PAGE_SHIFT);
                sg_set_page(&sg[i], page, page_size, 0);
-               va += page_size;
+               pa += page_size;
        }
        return sg;
-p2p_sg_err:
-       kfree(sg);
-       return NULL;
 }
 
 /* Init p2p mappings required to access peerdev from scifdev */
@@ -395,14 +390,14 @@ scif_init_p2p_info(struct scif_dev *scifdev, struct scif_dev *peerdev)
        p2p = kzalloc(sizeof(*p2p), GFP_KERNEL);
        if (!p2p)
                return NULL;
-       p2p->ppi_sg[SCIF_PPI_MMIO] = scif_p2p_setsg(psdev->mmio->va,
+       p2p->ppi_sg[SCIF_PPI_MMIO] = scif_p2p_setsg(psdev->mmio->pa,
                                                    PAGE_SIZE, num_mmio_pages);
        if (!p2p->ppi_sg[SCIF_PPI_MMIO])
                goto free_p2p;
        p2p->sg_nentries[SCIF_PPI_MMIO] = num_mmio_pages;
        sg_page_shift = get_order(min(psdev->aper->len, (u64)(1 << 30)));
        num_aper_chunks = num_aper_pages >> (sg_page_shift - PAGE_SHIFT);
-       p2p->ppi_sg[SCIF_PPI_APER] = scif_p2p_setsg(psdev->aper->va,
+       p2p->ppi_sg[SCIF_PPI_APER] = scif_p2p_setsg(psdev->aper->pa,
                                                    1 << sg_page_shift,
                                                    num_aper_chunks);
        p2p->sg_nentries[SCIF_PPI_APER] = num_aper_chunks;
index c9c3d20b784b669bf130cffb716b8525470738fa..a1b820fcb2a6ff60093011d696761ba4ca15e584 100644 (file)
@@ -208,6 +208,8 @@ static ssize_t power_ro_lock_show(struct device *dev,
 
        ret = snprintf(buf, PAGE_SIZE, "%d\n", locked);
 
+       mmc_blk_put(md);
+
        return ret;
 }
 
index fd9a58e216a50ffde01e8e9fb7610ef09c417af3..6a0f9c79be2652bdf843c40692e7dd188d76567a 100644 (file)
@@ -779,6 +779,7 @@ config MMC_TOSHIBA_PCI
 
 config MMC_MTK
        tristate "MediaTek SD/MMC Card Interface support"
+       depends on HAS_DMA
        help
          This selects the MediaTek(R) Secure digital and Multimedia card Interface.
          If you have a machine with a integrated SD/MMC card reader, say Y or M here.
index b2b411da297b06e73441f8dd51c8bae0b004bcc0..4d120323689043f21c522b44389757f8391d45fc 100644 (file)
@@ -1062,9 +1062,14 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 
                if (status & (CTO_EN | CCRC_EN))
                        end_cmd = 1;
+               if (host->data || host->response_busy) {
+                       end_trans = !end_cmd;
+                       host->response_busy = 0;
+               }
                if (status & (CTO_EN | DTO_EN))
                        hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd);
-               else if (status & (CCRC_EN | DCRC_EN))
+               else if (status & (CCRC_EN | DCRC_EN | DEB_EN | CEB_EN |
+                                  BADA_EN))
                        hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
 
                if (status & ACE_EN) {
@@ -1081,10 +1086,6 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
                        }
                        dev_dbg(mmc_dev(host->mmc), "AC12 err: 0x%x\n", ac12);
                }
-               if (host->data || host->response_busy) {
-                       end_trans = !end_cmd;
-                       host->response_busy = 0;
-               }
        }
 
        OMAP_HSMMC_WRITE(host->base, STAT, status);
index faf0cb910c968abcce26c431422adff3e438f81d..c6b9f6492e1a2529b7f683686bc4d939229dba63 100644 (file)
@@ -581,13 +581,8 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
 static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct pltfm_imx_data *imx_data = pltfm_host->priv;
-       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
 
-       if (boarddata->f_max && (boarddata->f_max < pltfm_host->clock))
-               return boarddata->f_max;
-       else
-               return pltfm_host->clock;
+       return pltfm_host->clock;
 }
 
 static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
@@ -878,34 +873,19 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
 static int
 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
                         struct sdhci_host *host,
-                        struct esdhc_platform_data *boarddata)
+                        struct pltfm_imx_data *imx_data)
 {
        struct device_node *np = pdev->dev.of_node;
-
-       if (!np)
-               return -ENODEV;
-
-       if (of_get_property(np, "non-removable", NULL))
-               boarddata->cd_type = ESDHC_CD_PERMANENT;
-
-       if (of_get_property(np, "fsl,cd-controller", NULL))
-               boarddata->cd_type = ESDHC_CD_CONTROLLER;
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
+       int ret;
 
        if (of_get_property(np, "fsl,wp-controller", NULL))
                boarddata->wp_type = ESDHC_WP_CONTROLLER;
 
-       boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
-       if (gpio_is_valid(boarddata->cd_gpio))
-               boarddata->cd_type = ESDHC_CD_GPIO;
-
        boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
        if (gpio_is_valid(boarddata->wp_gpio))
                boarddata->wp_type = ESDHC_WP_GPIO;
 
-       of_property_read_u32(np, "bus-width", &boarddata->max_bus_width);
-
-       of_property_read_u32(np, "max-frequency", &boarddata->f_max);
-
        if (of_find_property(np, "no-1-8-v", NULL))
                boarddata->support_vsel = false;
        else
@@ -916,29 +896,119 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
 
        mmc_of_parse_voltage(np, &host->ocr_mask);
 
+       /* sdr50 and sdr104 needs work on 1.8v signal voltage */
+       if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) &&
+           !IS_ERR(imx_data->pins_default)) {
+               imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
+                                               ESDHC_PINCTRL_STATE_100MHZ);
+               imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
+                                               ESDHC_PINCTRL_STATE_200MHZ);
+               if (IS_ERR(imx_data->pins_100mhz) ||
+                               IS_ERR(imx_data->pins_200mhz)) {
+                       dev_warn(mmc_dev(host->mmc),
+                               "could not get ultra high speed state, work on normal mode\n");
+                       /*
+                        * fall back to not support uhs by specify no 1.8v quirk
+                        */
+                       host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+               }
+       } else {
+               host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+       }
+
        /* call to generic mmc_of_parse to support additional capabilities */
-       return mmc_of_parse(host->mmc);
+       ret = mmc_of_parse(host->mmc);
+       if (ret)
+               return ret;
+
+       if (!IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc)))
+               host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+
+       return 0;
 }
 #else
 static inline int
 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
                         struct sdhci_host *host,
-                        struct esdhc_platform_data *boarddata)
+                        struct pltfm_imx_data *imx_data)
 {
        return -ENODEV;
 }
 #endif
 
+static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
+                        struct sdhci_host *host,
+                        struct pltfm_imx_data *imx_data)
+{
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
+       int err;
+
+       if (!host->mmc->parent->platform_data) {
+               dev_err(mmc_dev(host->mmc), "no board data!\n");
+               return -EINVAL;
+       }
+
+       imx_data->boarddata = *((struct esdhc_platform_data *)
+                               host->mmc->parent->platform_data);
+       /* write_protect */
+       if (boarddata->wp_type == ESDHC_WP_GPIO) {
+               err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio);
+               if (err) {
+                       dev_err(mmc_dev(host->mmc),
+                               "failed to request write-protect gpio!\n");
+                       return err;
+               }
+               host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
+       }
+
+       /* card_detect */
+       switch (boarddata->cd_type) {
+       case ESDHC_CD_GPIO:
+               err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0);
+               if (err) {
+                       dev_err(mmc_dev(host->mmc),
+                               "failed to request card-detect gpio!\n");
+                       return err;
+               }
+               /* fall through */
+
+       case ESDHC_CD_CONTROLLER:
+               /* we have a working card_detect back */
+               host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+               break;
+
+       case ESDHC_CD_PERMANENT:
+               host->mmc->caps |= MMC_CAP_NONREMOVABLE;
+               break;
+
+       case ESDHC_CD_NONE:
+               break;
+       }
+
+       switch (boarddata->max_bus_width) {
+       case 8:
+               host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
+               break;
+       case 4:
+               host->mmc->caps |= MMC_CAP_4_BIT_DATA;
+               break;
+       case 1:
+       default:
+               host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
+               break;
+       }
+
+       return 0;
+}
+
 static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id =
                        of_match_device(imx_esdhc_dt_ids, &pdev->dev);
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_host *host;
-       struct esdhc_platform_data *boarddata;
        int err;
        struct pltfm_imx_data *imx_data;
-       bool dt = true;
 
        host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 0);
        if (IS_ERR(host))
@@ -1030,84 +1100,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
        if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
                host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
 
-       boarddata = &imx_data->boarddata;
-       if (sdhci_esdhc_imx_probe_dt(pdev, host, boarddata) < 0) {
-               if (!host->mmc->parent->platform_data) {
-                       dev_err(mmc_dev(host->mmc), "no board data!\n");
-                       err = -EINVAL;
-                       goto disable_clk;
-               }
-               imx_data->boarddata = *((struct esdhc_platform_data *)
-                                       host->mmc->parent->platform_data);
-               dt = false;
-       }
-       /* write_protect */
-       if (boarddata->wp_type == ESDHC_WP_GPIO && !dt) {
-               err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio);
-               if (err) {
-                       dev_err(mmc_dev(host->mmc),
-                               "failed to request write-protect gpio!\n");
-                       goto disable_clk;
-               }
-               host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
-       }
-
-       /* card_detect */
-       switch (boarddata->cd_type) {
-       case ESDHC_CD_GPIO:
-               if (dt)
-                       break;
-               err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0);
-               if (err) {
-                       dev_err(mmc_dev(host->mmc),
-                               "failed to request card-detect gpio!\n");
-                       goto disable_clk;
-               }
-               /* fall through */
-
-       case ESDHC_CD_CONTROLLER:
-               /* we have a working card_detect back */
-               host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
-               break;
-
-       case ESDHC_CD_PERMANENT:
-               host->mmc->caps |= MMC_CAP_NONREMOVABLE;
-               break;
-
-       case ESDHC_CD_NONE:
-               break;
-       }
-
-       switch (boarddata->max_bus_width) {
-       case 8:
-               host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
-               break;
-       case 4:
-               host->mmc->caps |= MMC_CAP_4_BIT_DATA;
-               break;
-       case 1:
-       default:
-               host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
-               break;
-       }
-
-       /* sdr50 and sdr104 needs work on 1.8v signal voltage */
-       if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) &&
-           !IS_ERR(imx_data->pins_default)) {
-               imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
-                                               ESDHC_PINCTRL_STATE_100MHZ);
-               imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
-                                               ESDHC_PINCTRL_STATE_200MHZ);
-               if (IS_ERR(imx_data->pins_100mhz) ||
-                               IS_ERR(imx_data->pins_200mhz)) {
-                       dev_warn(mmc_dev(host->mmc),
-                               "could not get ultra high speed state, work on normal mode\n");
-                       /* fall back to not support uhs by specify no 1.8v quirk */
-                       host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
-               }
-       } else {
-               host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
-       }
+       if (of_id)
+               err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
+       else
+               err = sdhci_esdhc_imx_probe_nondt(pdev, host, imx_data);
+       if (err)
+               goto disable_clk;
 
        err = sdhci_add_host(host);
        if (err)
index 3497cfaf683c539edbd062199e03f5692e43bb26..a870c42731d7a4eea86b39e9e965d94a0603631d 100644 (file)
@@ -45,6 +45,6 @@
 #define ESDHC_DMA_SYSCTL       0x40c
 #define ESDHC_DMA_SNOOP                0x00000040
 
-#define ESDHC_HOST_CONTROL_RES 0x05
+#define ESDHC_HOST_CONTROL_RES 0x01
 
 #endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
index 9cd5fc62f130871aaa6390ac8e25b0f0f2fedf03..946d37f94a31b29e8739304ec71cf7b1468eead6 100644 (file)
@@ -411,6 +411,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
                        goto err_of_parse;
                sdhci_get_of_property(pdev);
                pdata = pxav3_get_mmc_pdata(dev);
+               pdev->dev.platform_data = pdata;
        } else if (pdata) {
                /* on-chip device */
                if (pdata->flags & PXA_FLAG_CARD_PERMANENT)
index bc1445238fb3053b8d2a03a7bb35a25ddfff4b61..1dbe932320309fc87f75a40cc2552ba5a784d5bd 100644 (file)
@@ -2866,6 +2866,7 @@ int sdhci_add_host(struct sdhci_host *host)
        u32 max_current_caps;
        unsigned int ocr_avail;
        unsigned int override_timeout_clk;
+       u32 max_clk;
        int ret;
 
        WARN_ON(host == NULL);
@@ -2978,8 +2979,11 @@ int sdhci_add_host(struct sdhci_host *host)
                                                      GFP_KERNEL);
                host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);
                if (!host->adma_table || !host->align_buffer) {
-                       dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
-                                         host->adma_table, host->adma_addr);
+                       if (host->adma_table)
+                               dma_free_coherent(mmc_dev(mmc),
+                                                 host->adma_table_sz,
+                                                 host->adma_table,
+                                                 host->adma_addr);
                        kfree(host->align_buffer);
                        pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
                                mmc_hostname(mmc));
@@ -3047,18 +3051,22 @@ int sdhci_add_host(struct sdhci_host *host)
         * Set host parameters.
         */
        mmc->ops = &sdhci_ops;
-       mmc->f_max = host->max_clk;
+       max_clk = host->max_clk;
+
        if (host->ops->get_min_clock)
                mmc->f_min = host->ops->get_min_clock(host);
        else if (host->version >= SDHCI_SPEC_300) {
                if (host->clk_mul) {
                        mmc->f_min = (host->max_clk * host->clk_mul) / 1024;
-                       mmc->f_max = host->max_clk * host->clk_mul;
+                       max_clk = host->max_clk * host->clk_mul;
                } else
                        mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
        } else
                mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
+       if (!mmc->f_max || (mmc->f_max && (mmc->f_max > max_clk)))
+               mmc->f_max = max_clk;
+
        if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
                host->timeout_clk = (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >>
                                        SDHCI_TIMEOUT_CLK_SHIFT;
index 317a49480475d2c87fb5a4aa56716844ce21005a..a98dd4f1b0e33126ca04d1a7cecb8ad1e41d8d72 100644 (file)
@@ -625,6 +625,23 @@ static void bond_set_dev_addr(struct net_device *bond_dev,
        call_netdevice_notifiers(NETDEV_CHANGEADDR, bond_dev);
 }
 
+static struct slave *bond_get_old_active(struct bonding *bond,
+                                        struct slave *new_active)
+{
+       struct slave *slave;
+       struct list_head *iter;
+
+       bond_for_each_slave(bond, slave, iter) {
+               if (slave == new_active)
+                       continue;
+
+               if (ether_addr_equal(bond->dev->dev_addr, slave->dev->dev_addr))
+                       return slave;
+       }
+
+       return NULL;
+}
+
 /* bond_do_fail_over_mac
  *
  * Perform special MAC address swapping for fail_over_mac settings
@@ -652,6 +669,9 @@ static void bond_do_fail_over_mac(struct bonding *bond,
                if (!new_active)
                        return;
 
+               if (!old_active)
+                       old_active = bond_get_old_active(bond, new_active);
+
                if (old_active) {
                        ether_addr_copy(tmp_mac, new_active->dev->dev_addr);
                        ether_addr_copy(saddr.sa_data,
@@ -766,6 +786,7 @@ static bool bond_should_notify_peers(struct bonding *bond)
                   slave ? slave->dev->name : "NULL");
 
        if (!slave || !bond->send_peer_notif ||
+           !netif_carrier_ok(bond->dev) ||
            test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
                return false;
 
@@ -1725,9 +1746,16 @@ err_free:
 
 err_undo_flags:
        /* Enslave of first slave has failed and we need to fix master's mac */
-       if (!bond_has_slaves(bond) &&
-           ether_addr_equal_64bits(bond_dev->dev_addr, slave_dev->dev_addr))
-               eth_hw_addr_random(bond_dev);
+       if (!bond_has_slaves(bond)) {
+               if (ether_addr_equal_64bits(bond_dev->dev_addr,
+                                           slave_dev->dev_addr))
+                       eth_hw_addr_random(bond_dev);
+               if (bond_dev->type != ARPHRD_ETHER) {
+                       ether_setup(bond_dev);
+                       bond_dev->flags |= IFF_MASTER;
+                       bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+               }
+       }
 
        return res;
 }
@@ -1916,6 +1944,7 @@ static int  bond_release_and_destroy(struct net_device *bond_dev,
                bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
                netdev_info(bond_dev, "Destroying bond %s\n",
                            bond_dev->name);
+               bond_remove_proc_entry(bond);
                unregister_netdevice(bond_dev);
        }
        return ret;
index f4e40aa4d2a21db2be91eb39f46d1e410ac6c0e0..945c0955a9675198a8b0945ddc49dd6668380838 100644 (file)
@@ -577,10 +577,10 @@ static void at91_rx_overflow_err(struct net_device *dev)
 
        cf->can_id |= CAN_ERR_CRTL;
        cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
-       netif_receive_skb(skb);
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 }
 
 /**
@@ -642,10 +642,10 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
        }
 
        at91_read_mb(dev, mb, cf);
-       netif_receive_skb(skb);
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        can_led_event(dev, CAN_LED_EVENT_RX);
 }
@@ -802,10 +802,10 @@ static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr)
                return 0;
 
        at91_poll_err_frame(dev, cf, reg_sr);
-       netif_receive_skb(skb);
 
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        return 1;
 }
@@ -1067,10 +1067,10 @@ static void at91_irq_err(struct net_device *dev)
                return;
 
        at91_irq_err_state(dev, cf, new_state);
-       netif_rx(skb);
 
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        priv->can.state = new_state;
 }
index 27ad312e7abf34bdf94a86ce66fa5ae900da1aed..57dadd52b428a536d71f2364c006641e5e765083 100644 (file)
@@ -424,10 +424,9 @@ static void bfin_can_rx(struct net_device *dev, u16 isrc)
                cf->data[6 - i] = (6 - i) < cf->can_dlc ? (val >> 8) : 0;
        }
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
@@ -508,10 +507,9 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
 
        priv->can.state = state;
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
index c11d4498403617e4dddcea42d085e08355c9a5d2..70a8cbb29e75844a02bea49a937bf0c05a200910 100644 (file)
@@ -504,10 +504,10 @@ static void cc770_rx(struct net_device *dev, unsigned int mo, u8 ctrl1)
                for (i = 0; i < cf->can_dlc; i++)
                        cf->data[i] = cc770_read_reg(priv, msgobj[mo].data[i]);
        }
-       netif_rx(skb);
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 static int cc770_err(struct net_device *dev, u8 status)
@@ -584,10 +584,10 @@ static int cc770_err(struct net_device *dev, u8 status)
                }
        }
 
-       netif_rx(skb);
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
index 6201c5a1a8845f2e3e68f3921a2fcae8e4469217..b1e8d729851cbb5173c1bbec2b34c4893b2ff595 100644 (file)
@@ -577,10 +577,10 @@ static int flexcan_poll_bus_err(struct net_device *dev, u32 reg_esr)
                return 0;
 
        do_bus_err(dev, cf, reg_esr);
-       netif_receive_skb(skb);
 
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        return 1;
 }
@@ -622,10 +622,9 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
        if (unlikely(new_state == CAN_STATE_BUS_OFF))
                can_bus_off(dev);
 
-       netif_receive_skb(skb);
-
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        return 1;
 }
@@ -670,10 +669,10 @@ static int flexcan_read_frame(struct net_device *dev)
        }
 
        flexcan_read_fifo(dev, cf);
-       netif_receive_skb(skb);
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        can_led_event(dev, CAN_LED_EVENT_RX);
 
index e3d7e22a4fa080504544a245d9e21adb80aea036..db9538d4b3586e7357ae8d46e4db9f25a27cd469 100644 (file)
@@ -1216,11 +1216,12 @@ static int grcan_receive(struct net_device *dev, int budget)
                                cf->data[i] = (u8)(slot[j] >> shift);
                        }
                }
-               netif_receive_skb(skb);
 
                /* Update statistics and read pointer */
                stats->rx_packets++;
                stats->rx_bytes += cf->can_dlc;
+               netif_receive_skb(skb);
+
                rd = grcan_ring_add(rd, GRCAN_MSG_SIZE, dma->rx.size);
        }
 
index 32bd7f451aa42b53f0a479af667861db6693d619..7b92e911a6168badb3e30f8fc55b2e6fdd0f61dc 100644 (file)
@@ -377,10 +377,9 @@ static void sja1000_rx(struct net_device *dev)
        /* release receive buffer */
        sja1000_write_cmdreg(priv, CMD_RRB);
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        can_led_event(dev, CAN_LED_EVENT_RX);
 }
@@ -484,10 +483,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
                        can_bus_off(dev);
        }
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
index a23a7af8eb9a0ccfdffc39518ee9ee7cd43485d1..9a3f15cb7ef4883abebe6bac8ffc5909077d475f 100644 (file)
@@ -218,10 +218,10 @@ static void slc_bump(struct slcan *sl)
 
        memcpy(skb_put(skb, sizeof(struct can_frame)),
               &cf, sizeof(struct can_frame));
-       netif_rx_ni(skb);
 
        sl->dev->stats.rx_packets++;
        sl->dev->stats.rx_bytes += cf.can_dlc;
+       netif_rx_ni(skb);
 }
 
 /* parse tty input stream */
index c1a95a34d62ea682d8a2582ddc068ca52c7e592d..b7e83c2120235e133141422ebe037a3bf43e7a15 100644 (file)
@@ -1086,8 +1086,8 @@ static int mcp251x_can_probe(struct spi_device *spi)
        if (ret)
                goto out_clk;
 
-       priv->power = devm_regulator_get(&spi->dev, "vdd");
-       priv->transceiver = devm_regulator_get(&spi->dev, "xceiver");
+       priv->power = devm_regulator_get_optional(&spi->dev, "vdd");
+       priv->transceiver = devm_regulator_get_optional(&spi->dev, "xceiver");
        if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
            (PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) {
                ret = -EPROBE_DEFER;
@@ -1222,17 +1222,16 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
        struct spi_device *spi = to_spi_device(dev);
        struct mcp251x_priv *priv = spi_get_drvdata(spi);
 
-       if (priv->after_suspend & AFTER_SUSPEND_POWER) {
+       if (priv->after_suspend & AFTER_SUSPEND_POWER)
                mcp251x_power_enable(priv->power, 1);
+
+       if (priv->after_suspend & AFTER_SUSPEND_UP) {
+               mcp251x_power_enable(priv->transceiver, 1);
                queue_work(priv->wq, &priv->restart_work);
        } else {
-               if (priv->after_suspend & AFTER_SUSPEND_UP) {
-                       mcp251x_power_enable(priv->transceiver, 1);
-                       queue_work(priv->wq, &priv->restart_work);
-               } else {
-                       priv->after_suspend = 0;
-               }
+               priv->after_suspend = 0;
        }
+
        priv->force_quit = 0;
        enable_irq(spi->irq);
        return 0;
index e95a9e1a889f19c4673d9735e5e932eb83340767..cf345cbfe8198ef23ee328fc2eb67f5841751ee1 100644 (file)
@@ -747,9 +747,9 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
                }
        }
 
-       netif_rx(skb);
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
index 866bac0ae7e966855d1085f5a8735988832a1bb7..2d390384ef3bb3d3845fcf6102bef70715f1dd21 100644 (file)
@@ -324,10 +324,9 @@ static void ems_usb_rx_can_msg(struct ems_usb *dev, struct ems_cpc_msg *msg)
                        cf->data[i] = msg->msg.can_msg.msg[i];
        }
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
@@ -400,10 +399,9 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
                stats->rx_errors++;
        }
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 /*
index 411c1af92c62c1c93985e4adf7232d1b6b78d8bc..0e5a4493ba4fee6d3c4fb5626a676f18802a6ef3 100644 (file)
@@ -301,13 +301,12 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
                        cf->data[7] = rxerr;
                }
 
-               netif_rx(skb);
-
                priv->bec.txerr = txerr;
                priv->bec.rxerr = rxerr;
 
                stats->rx_packets++;
                stats->rx_bytes += cf->can_dlc;
+               netif_rx(skb);
        }
 }
 
@@ -347,10 +346,9 @@ static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
                                cf->data[i] = msg->msg.rx.data[i];
                }
 
-               netif_rx(skb);
-
                stats->rx_packets++;
                stats->rx_bytes += cf->can_dlc;
+               netif_rx(skb);
        }
 
        return;
index 72427f21edffaa9fed0874085e277aa4c83783b7..6b94007ae05221c94d3dedce77a412e732834337 100644 (file)
@@ -526,9 +526,9 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
                hwts->hwtstamp = timeval_to_ktime(tv);
        }
 
-       netif_rx(skb);
        mc->netdev->stats.rx_packets++;
        mc->netdev->stats.rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
@@ -659,12 +659,11 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
        hwts = skb_hwtstamps(skb);
        hwts->hwtstamp = timeval_to_ktime(tv);
 
-       /* push the skb */
-       netif_rx(skb);
-
        /* update statistics */
        mc->netdev->stats.rx_packets++;
        mc->netdev->stats.rx_bytes += cf->can_dlc;
+       /* push the skb */
+       netif_rx(skb);
 
        return 0;
 
index dec51717635e900aafc91b771e5bfa0a2b594fae..7d61b3279798b936f4a3238afb57c73437ba22f2 100644 (file)
@@ -553,9 +553,9 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
        hwts = skb_hwtstamps(skb);
        hwts->hwtstamp = timeval_to_ktime(tv);
 
-       netif_rx(skb);
        netdev->stats.rx_packets++;
        netdev->stats.rx_bytes += can_frame->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
@@ -670,9 +670,9 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
        peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv);
        hwts = skb_hwtstamps(skb);
        hwts->hwtstamp = timeval_to_ktime(tv);
-       netif_rx(skb);
        netdev->stats.rx_packets++;
        netdev->stats.rx_bytes += can_frame->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
index dd52c7a4c80d9f26faa74ece8d109ee21045ba47..de95b1ccba3e3b6d4d00e313acb280cd178a000d 100644 (file)
@@ -461,10 +461,9 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
        priv->bec.txerr = txerr;
        priv->bec.rxerr = rxerr;
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 /* Read data and status frames */
@@ -494,10 +493,9 @@ static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv,
                else
                        memcpy(cf->data, msg->data, cf->can_dlc);
 
-               netif_rx(skb);
-
                stats->rx_packets++;
                stats->rx_bytes += cf->can_dlc;
+               netif_rx(skb);
 
                can_led_event(priv->netdev, CAN_LED_EVENT_RX);
        } else {
index 972982f8bea7af16f253b58d3540cc0b9aa6682b..079897b3a9554b55918c97a94f5ba718c314da38 100644 (file)
@@ -696,9 +696,20 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
        }
 
        /* Include the pseudo-PHY address and the broadcast PHY address to
-        * divert reads towards our workaround
+        * divert reads towards our workaround. This is only required for
+        * 7445D0, since 7445E0 disconnects the internal switch pseudo-PHY such
+        * that we can use the regular SWITCH_MDIO master controller instead.
+        *
+        * By default, DSA initializes ds->phys_mii_mask to ds->phys_port_mask
+        * to have a 1:1 mapping between Port address and PHY address in order
+        * to utilize the slave_mii_bus instance to read from Port PHYs. This is
+        * not what we want here, so we initialize phys_mii_mask 0 to always
+        * utilize the "master" MDIO bus backed by the "mdio-unimac" driver.
         */
-       ds->phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0));
+       if (of_machine_is_compatible("brcm,bcm7445d0"))
+               ds->phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0));
+       else
+               ds->phys_mii_mask = 0;
 
        rev = reg_readl(priv, REG_SWITCH_REVISION);
        priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
index fd8547c2b79d46786b10807a0c62f338b6a60e27..561342466076c57888bcd92b4f463756f4d10a49 100644 (file)
@@ -1163,7 +1163,7 @@ int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
 
        newfid = __ffs(ps->fid_mask);
        ps->fid[port] = newfid;
-       ps->fid_mask &= (1 << newfid);
+       ps->fid_mask &= ~(1 << newfid);
        ps->bridge_mask[fid] &= ~(1 << port);
        ps->bridge_mask[newfid] = 1 << port;
 
index 2d1ce3c5d0dd34c9fabb1399a32c49be744afdd1..753887d02b46abc66663a24a2ea3e4e396d6b881 100644 (file)
@@ -1763,16 +1763,9 @@ vortex_open(struct net_device *dev)
                        vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
                }
                if (i != RX_RING_SIZE) {
-                       int j;
                        pr_emerg("%s: no memory for rx ring\n", dev->name);
-                       for (j = 0; j < i; j++) {
-                               if (vp->rx_skbuff[j]) {
-                                       dev_kfree_skb(vp->rx_skbuff[j]);
-                                       vp->rx_skbuff[j] = NULL;
-                               }
-                       }
                        retval = -ENOMEM;
-                       goto err_free_irq;
+                       goto err_free_skb;
                }
                /* Wrap the ring. */
                vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
@@ -1782,7 +1775,13 @@ vortex_open(struct net_device *dev)
        if (!retval)
                goto out;
 
-err_free_irq:
+err_free_skb:
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               if (vp->rx_skbuff[i]) {
+                       dev_kfree_skb(vp->rx_skbuff[i]);
+                       vp->rx_skbuff[i] = NULL;
+               }
+       }
        free_irq(dev->irq, dev);
 err:
        if (vortex_debug > 1)
index a90d7364334f9dfa3687dc813e068508a342861c..f7fbdc9d132511b72df0db2ce0b92e4df0774c44 100644 (file)
@@ -262,9 +262,9 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
        if (likely(skb)) {
                (*pkts_compl)++;
                (*bytes_compl) += skb->len;
+               dev_kfree_skb_any(skb);
        }
 
-       dev_kfree_skb_any(skb);
        tx_buf->first_bd = 0;
        tx_buf->skb = NULL;
 
index 76b9052a961c517978494199d74398264583508c..5907c821d131eed6fa5b6b0aa7a93dc41cca0d66 100644 (file)
@@ -1718,6 +1718,22 @@ static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf,
                offset += sizeof(u32);
                data_buf += sizeof(u32);
                written_so_far += sizeof(u32);
+
+               /* At end of each 4Kb page, release nvram lock to allow MFW
+                * chance to take it for its own use.
+                */
+               if ((cmd_flags & MCPR_NVM_COMMAND_LAST) &&
+                   (written_so_far < buf_size)) {
+                       DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
+                          "Releasing NVM lock after offset 0x%x\n",
+                          (u32)(offset - sizeof(u32)));
+                       bnx2x_release_nvram_lock(bp);
+                       usleep_range(1000, 2000);
+                       rc = bnx2x_acquire_nvram_lock(bp);
+                       if (rc)
+                               return rc;
+               }
+
                cmd_flags = 0;
        }
 
index 0612b19f6313bd3e6ffa205be2b543585262e31e..506047c386071db9472d60218faa004fe94849a8 100644 (file)
@@ -676,6 +676,7 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
                        if (!next_cmpl->valid)
                                break;
                }
+               packets++;
 
                /* TODO: BNA_CQ_EF_LOCAL ? */
                if (unlikely(flags & (BNA_CQ_EF_MAC_ERROR |
@@ -692,7 +693,6 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
                else
                        bnad_cq_setup_skb_frags(rcb, skb, sop_ci, nvecs, len);
 
-               packets++;
                rcb->rxq->rx_packets++;
                rcb->rxq->rx_bytes += totlen;
                ccb->bytes_per_intr += totlen;
index caeb39561567237261ac0d50befebad666cfbeb3..bf9eb2ecf96003e066418d93c7d22aae89c76a31 100644 (file)
@@ -104,6 +104,57 @@ static void *macb_rx_buffer(struct macb *bp, unsigned int index)
        return bp->rx_buffers + bp->rx_buffer_size * macb_rx_ring_wrap(index);
 }
 
+/* I/O accessors */
+static u32 hw_readl_native(struct macb *bp, int offset)
+{
+       return __raw_readl(bp->regs + offset);
+}
+
+static void hw_writel_native(struct macb *bp, int offset, u32 value)
+{
+       __raw_writel(value, bp->regs + offset);
+}
+
+static u32 hw_readl(struct macb *bp, int offset)
+{
+       return readl_relaxed(bp->regs + offset);
+}
+
+static void hw_writel(struct macb *bp, int offset, u32 value)
+{
+       writel_relaxed(value, bp->regs + offset);
+}
+
+/*
+ * Find the CPU endianness by using the loopback bit of NCR register. When the
+ * CPU is in big endian we need to program swaped mode for management
+ * descriptor access.
+ */
+static bool hw_is_native_io(void __iomem *addr)
+{
+       u32 value = MACB_BIT(LLB);
+
+       __raw_writel(value, addr + MACB_NCR);
+       value = __raw_readl(addr + MACB_NCR);
+
+       /* Write 0 back to disable everything */
+       __raw_writel(0, addr + MACB_NCR);
+
+       return value == MACB_BIT(LLB);
+}
+
+static bool hw_is_gem(void __iomem *addr, bool native_io)
+{
+       u32 id;
+
+       if (native_io)
+               id = __raw_readl(addr + MACB_MID);
+       else
+               id = readl_relaxed(addr + MACB_MID);
+
+       return MACB_BFEXT(IDNUM, id) >= 0x2;
+}
+
 static void macb_set_hwaddr(struct macb *bp)
 {
        u32 bottom;
@@ -160,7 +211,7 @@ static void macb_get_hwaddr(struct macb *bp)
                }
        }
 
-       netdev_info(bp->dev, "invalid hw address, using random\n");
+       dev_info(&bp->pdev->dev, "invalid hw address, using random\n");
        eth_hw_addr_random(bp->dev);
 }
 
@@ -252,7 +303,6 @@ static void macb_handle_link_change(struct net_device *dev)
        struct macb *bp = netdev_priv(dev);
        struct phy_device *phydev = bp->phy_dev;
        unsigned long flags;
-
        int status_change = 0;
 
        spin_lock_irqsave(&bp->lock, flags);
@@ -449,14 +499,14 @@ err_out:
 
 static void macb_update_stats(struct macb *bp)
 {
-       u32 __iomem *reg = bp->regs + MACB_PFR;
        u32 *p = &bp->hw_stats.macb.rx_pause_frames;
        u32 *end = &bp->hw_stats.macb.tx_pause_frames + 1;
+       int offset = MACB_PFR;
 
        WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4);
 
-       for(; p < end; p++, reg++)
-               *p += readl_relaxed(reg);
+       for(; p < end; p++, offset += 4)
+               *p += bp->macb_reg_readl(bp, offset);
 }
 
 static int macb_halt_tx(struct macb *bp)
@@ -1107,12 +1157,6 @@ static void macb_poll_controller(struct net_device *dev)
 }
 #endif
 
-static inline unsigned int macb_count_tx_descriptors(struct macb *bp,
-                                                    unsigned int len)
-{
-       return (len + bp->max_tx_length - 1) / bp->max_tx_length;
-}
-
 static unsigned int macb_tx_map(struct macb *bp,
                                struct macb_queue *queue,
                                struct sk_buff *skb)
@@ -1263,11 +1307,11 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
         * socket buffer: skb fragments of jumbo frames may need to be
         * splitted into many buffer descriptors.
         */
-       count = macb_count_tx_descriptors(bp, skb_headlen(skb));
+       count = DIV_ROUND_UP(skb_headlen(skb), bp->max_tx_length);
        nr_frags = skb_shinfo(skb)->nr_frags;
        for (f = 0; f < nr_frags; f++) {
                frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]);
-               count += macb_count_tx_descriptors(bp, frag_size);
+               count += DIV_ROUND_UP(frag_size, bp->max_tx_length);
        }
 
        spin_lock_irqsave(&bp->lock, flags);
@@ -1603,7 +1647,6 @@ static u32 macb_dbw(struct macb *bp)
 static void macb_configure_dma(struct macb *bp)
 {
        u32 dmacfg;
-       u32 tmp, ncr;
 
        if (macb_is_gem(bp)) {
                dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L);
@@ -1613,22 +1656,11 @@ static void macb_configure_dma(struct macb *bp)
                dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
                dmacfg &= ~GEM_BIT(ENDIA_PKT);
 
-               /* Find the CPU endianness by using the loopback bit of net_ctrl
-                * register. save it first. When the CPU is in big endian we
-                * need to program swaped mode for management descriptor access.
-                */
-               ncr = macb_readl(bp, NCR);
-               __raw_writel(MACB_BIT(LLB), bp->regs + MACB_NCR);
-               tmp =  __raw_readl(bp->regs + MACB_NCR);
-
-               if (tmp == MACB_BIT(LLB))
+               if (bp->native_io)
                        dmacfg &= ~GEM_BIT(ENDIA_DESC);
                else
                        dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */
 
-               /* Restore net_ctrl */
-               macb_writel(bp, NCR, ncr);
-
                if (bp->dev->features & NETIF_F_HW_CSUM)
                        dmacfg |= GEM_BIT(TXCOEN);
                else
@@ -1897,19 +1929,19 @@ static int macb_change_mtu(struct net_device *dev, int new_mtu)
 
 static void gem_update_stats(struct macb *bp)
 {
-       int i;
+       unsigned int i;
        u32 *p = &bp->hw_stats.gem.tx_octets_31_0;
 
        for (i = 0; i < GEM_STATS_LEN; ++i, ++p) {
                u32 offset = gem_statistics[i].offset;
-               u64 val = readl_relaxed(bp->regs + offset);
+               u64 val = bp->macb_reg_readl(bp, offset);
 
                bp->ethtool_stats[i] += val;
                *p += val;
 
                if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) {
                        /* Add GEM_OCTTXH, GEM_OCTRXH */
-                       val = readl_relaxed(bp->regs + offset + 4);
+                       val = bp->macb_reg_readl(bp, offset + 4);
                        bp->ethtool_stats[i] += ((u64)val) << 32;
                        *(++p) += val;
                }
@@ -1976,7 +2008,7 @@ static int gem_get_sset_count(struct net_device *dev, int sset)
 
 static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p)
 {
-       int i;
+       unsigned int i;
 
        switch (sset) {
        case ETH_SS_STATS:
@@ -2190,7 +2222,7 @@ static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_co
        if (dt_conf)
                bp->caps = dt_conf->caps;
 
-       if (macb_is_gem_hw(bp->regs)) {
+       if (hw_is_gem(bp->regs, bp->native_io)) {
                bp->caps |= MACB_CAPS_MACB_IS_GEM;
 
                dcfg = gem_readl(bp, DCFG1);
@@ -2201,10 +2233,11 @@ static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_co
                        bp->caps |= MACB_CAPS_FIFO_MODE;
        }
 
-       netdev_dbg(bp->dev, "Cadence caps 0x%08x\n", bp->caps);
+       dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps);
 }
 
 static void macb_probe_queues(void __iomem *mem,
+                             bool native_io,
                              unsigned int *queue_mask,
                              unsigned int *num_queues)
 {
@@ -2219,7 +2252,7 @@ static void macb_probe_queues(void __iomem *mem,
         * we are early in the probe process and don't have the
         * MACB_CAPS_MACB_IS_GEM flag positioned
         */
-       if (!macb_is_gem_hw(mem))
+       if (!hw_is_gem(mem, native_io))
                return;
 
        /* bit 0 is never set but queue 0 always exists */
@@ -2786,6 +2819,7 @@ static int macb_probe(struct platform_device *pdev)
        struct clk *pclk, *hclk, *tx_clk;
        unsigned int queue_mask, num_queues;
        struct macb_platform_data *pdata;
+       bool native_io;
        struct phy_device *phydev;
        struct net_device *dev;
        struct resource *regs;
@@ -2794,6 +2828,11 @@ static int macb_probe(struct platform_device *pdev)
        struct macb *bp;
        int err;
 
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mem = devm_ioremap_resource(&pdev->dev, regs);
+       if (IS_ERR(mem))
+               return PTR_ERR(mem);
+
        if (np) {
                const struct of_device_id *match;
 
@@ -2809,14 +2848,9 @@ static int macb_probe(struct platform_device *pdev)
        if (err)
                return err;
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mem = devm_ioremap_resource(&pdev->dev, regs);
-       if (IS_ERR(mem)) {
-               err = PTR_ERR(mem);
-               goto err_disable_clocks;
-       }
+       native_io = hw_is_native_io(mem);
 
-       macb_probe_queues(mem, &queue_mask, &num_queues);
+       macb_probe_queues(mem, native_io, &queue_mask, &num_queues);
        dev = alloc_etherdev_mq(sizeof(*bp), num_queues);
        if (!dev) {
                err = -ENOMEM;
@@ -2831,6 +2865,14 @@ static int macb_probe(struct platform_device *pdev)
        bp->pdev = pdev;
        bp->dev = dev;
        bp->regs = mem;
+       bp->native_io = native_io;
+       if (native_io) {
+               bp->macb_reg_readl = hw_readl_native;
+               bp->macb_reg_writel = hw_writel_native;
+       } else {
+               bp->macb_reg_readl = hw_readl;
+               bp->macb_reg_writel = hw_writel;
+       }
        bp->num_queues = num_queues;
        bp->queue_mask = queue_mask;
        if (macb_config)
@@ -2838,9 +2880,8 @@ static int macb_probe(struct platform_device *pdev)
        bp->pclk = pclk;
        bp->hclk = hclk;
        bp->tx_clk = tx_clk;
-       if (macb_config->jumbo_max_len) {
+       if (macb_config)
                bp->jumbo_max_len = macb_config->jumbo_max_len;
-       }
 
        spin_lock_init(&bp->lock);
 
index d74655993d4bf19cec68ab227263f5f069467e4c..1895b6b2adddc00188b515004ca5359b860fdc0f 100644 (file)
         | GEM_BF(name, value))
 
 /* Register access macros */
-#define macb_readl(port,reg)                           \
-       readl_relaxed((port)->regs + MACB_##reg)
-#define macb_writel(port,reg,value)                    \
-       writel_relaxed((value), (port)->regs + MACB_##reg)
-#define gem_readl(port, reg)                           \
-       readl_relaxed((port)->regs + GEM_##reg)
-#define gem_writel(port, reg, value)                   \
-       writel_relaxed((value), (port)->regs + GEM_##reg)
-#define queue_readl(queue, reg)                                \
-       readl_relaxed((queue)->bp->regs + (queue)->reg)
-#define queue_writel(queue, reg, value)                        \
-       writel_relaxed((value), (queue)->bp->regs + (queue)->reg)
+#define macb_readl(port, reg)          (port)->macb_reg_readl((port), MACB_##reg)
+#define macb_writel(port, reg, value)  (port)->macb_reg_writel((port), MACB_##reg, (value))
+#define gem_readl(port, reg)           (port)->macb_reg_readl((port), GEM_##reg)
+#define gem_writel(port, reg, value)   (port)->macb_reg_writel((port), GEM_##reg, (value))
+#define queue_readl(queue, reg)                (queue)->bp->macb_reg_readl((queue)->bp, (queue)->reg)
+#define queue_writel(queue, reg, value)        (queue)->bp->macb_reg_writel((queue)->bp, (queue)->reg, (value))
 
 /* Conditional GEM/MACB macros.  These perform the operation to the correct
  * register dependent on whether the device is a GEM or a MACB.  For registers
@@ -785,6 +779,11 @@ struct macb_queue {
 
 struct macb {
        void __iomem            *regs;
+       bool                    native_io;
+
+       /* hardware IO accessors */
+       u32     (*macb_reg_readl)(struct macb *bp, int offset);
+       void    (*macb_reg_writel)(struct macb *bp, int offset, u32 value);
 
        unsigned int            rx_tail;
        unsigned int            rx_prepared_head;
@@ -817,9 +816,9 @@ struct macb {
 
        struct mii_bus          *mii_bus;
        struct phy_device       *phy_dev;
-       unsigned int            link;
-       unsigned int            speed;
-       unsigned int            duplex;
+       int                     link;
+       int                     speed;
+       int                     duplex;
 
        u32                     caps;
        unsigned int            dma_burst_length;
@@ -843,9 +842,4 @@ static inline bool macb_is_gem(struct macb *bp)
        return !!(bp->caps & MACB_CAPS_MACB_IS_GEM);
 }
 
-static inline bool macb_is_gem_hw(void __iomem *addr)
-{
-       return !!(MACB_BFEXT(IDNUM, readl_relaxed(addr + MACB_MID)) >= 0x2);
-}
-
 #endif /* _MACB_H */
index c4d6bbe9458dbfe9c726fdff1e9b6c4c64b8a33f..02e23e6f142487ddc8cc2a8d4e2c512cb7e6db62 100644 (file)
@@ -16,7 +16,6 @@ if NET_VENDOR_CAVIUM
 config THUNDER_NIC_PF
        tristate "Thunder Physical function driver"
        depends on 64BIT
-       default ARCH_THUNDER
        select THUNDER_NIC_BGX
        ---help---
          This driver supports Thunder's NIC physical function.
@@ -29,14 +28,12 @@ config THUNDER_NIC_PF
 config THUNDER_NIC_VF
        tristate "Thunder Virtual function driver"
        depends on 64BIT
-       default ARCH_THUNDER
        ---help---
          This driver supports Thunder's NIC virtual function
 
 config THUNDER_NIC_BGX
        tristate "Thunder MAC interface driver (BGX)"
        depends on 64BIT
-       default ARCH_THUNDER
        ---help---
          This driver supports programming and controlling of MAC
          interface from NIC physical function driver.
index dda8a02b7322d63197d583ab1c107226ea913051..8aee250904ec83de7b230bf186c3835e0957f46a 100644 (file)
  */
 #define NICPF_CLK_PER_INT_TICK         2
 
+/* Time to wait before we decide that a SQ is stuck.
+ *
+ * Since both pkt rx and tx notifications are done with same CQ,
+ * when packets are being received at very high rate (eg: L2 forwarding)
+ * then freeing transmitted skbs will be delayed and watchdog
+ * will kick in, resetting interface. Hence keeping this value high.
+ */
+#define        NICVF_TX_TIMEOUT                (50 * HZ)
+
 struct nicvf_cq_poll {
        u8      cq_idx;         /* Completion queue index */
        struct  napi_struct napi;
@@ -216,8 +225,9 @@ struct nicvf_drv_stats {
        /* Tx */
        u64 tx_frames_ok;
        u64 tx_drops;
-       u64 tx_busy;
        u64 tx_tso;
+       u64 txq_stop;
+       u64 txq_wake;
 };
 
 struct nicvf {
index 16bd2d772db9f81da0969f7594c4aa3b1761c30f..a4228e66456707d3da44e0cfce653b318b180444 100644 (file)
@@ -66,9 +66,10 @@ static const struct nicvf_stat nicvf_drv_stats[] = {
        NICVF_DRV_STAT(rx_frames_jumbo),
        NICVF_DRV_STAT(rx_drops),
        NICVF_DRV_STAT(tx_frames_ok),
-       NICVF_DRV_STAT(tx_busy),
        NICVF_DRV_STAT(tx_tso),
        NICVF_DRV_STAT(tx_drops),
+       NICVF_DRV_STAT(txq_stop),
+       NICVF_DRV_STAT(txq_wake),
 };
 
 static const struct nicvf_stat nicvf_queue_stats[] = {
@@ -126,6 +127,7 @@ static void nicvf_set_msglevel(struct net_device *netdev, u32 lvl)
 
 static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
 {
+       struct nicvf *nic = netdev_priv(netdev);
        int stats, qidx;
 
        if (sset != ETH_SS_STATS)
@@ -141,7 +143,7 @@ static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
                data += ETH_GSTRING_LEN;
        }
 
-       for (qidx = 0; qidx < MAX_RCV_QUEUES_PER_QS; qidx++) {
+       for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) {
                for (stats = 0; stats < nicvf_n_queue_stats; stats++) {
                        sprintf(data, "rxq%d: %s", qidx,
                                nicvf_queue_stats[stats].name);
@@ -149,7 +151,7 @@ static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
                }
        }
 
-       for (qidx = 0; qidx < MAX_SND_QUEUES_PER_QS; qidx++) {
+       for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) {
                for (stats = 0; stats < nicvf_n_queue_stats; stats++) {
                        sprintf(data, "txq%d: %s", qidx,
                                nicvf_queue_stats[stats].name);
@@ -170,12 +172,14 @@ static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
 
 static int nicvf_get_sset_count(struct net_device *netdev, int sset)
 {
+       struct nicvf *nic = netdev_priv(netdev);
+
        if (sset != ETH_SS_STATS)
                return -EINVAL;
 
        return nicvf_n_hw_stats + nicvf_n_drv_stats +
                (nicvf_n_queue_stats *
-                (MAX_RCV_QUEUES_PER_QS + MAX_SND_QUEUES_PER_QS)) +
+                (nic->qs->rq_cnt + nic->qs->sq_cnt)) +
                BGX_RX_STATS_COUNT + BGX_TX_STATS_COUNT;
 }
 
@@ -197,13 +201,13 @@ static void nicvf_get_ethtool_stats(struct net_device *netdev,
                *(data++) = ((u64 *)&nic->drv_stats)
                                [nicvf_drv_stats[stat].index];
 
-       for (qidx = 0; qidx < MAX_RCV_QUEUES_PER_QS; qidx++) {
+       for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) {
                for (stat = 0; stat < nicvf_n_queue_stats; stat++)
                        *(data++) = ((u64 *)&nic->qs->rq[qidx].stats)
                                        [nicvf_queue_stats[stat].index];
        }
 
-       for (qidx = 0; qidx < MAX_SND_QUEUES_PER_QS; qidx++) {
+       for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) {
                for (stat = 0; stat < nicvf_n_queue_stats; stat++)
                        *(data++) = ((u64 *)&nic->qs->sq[qidx].stats)
                                        [nicvf_queue_stats[stat].index];
@@ -543,6 +547,7 @@ static int nicvf_set_channels(struct net_device *dev,
 {
        struct nicvf *nic = netdev_priv(dev);
        int err = 0;
+       bool if_up = netif_running(dev);
 
        if (!channel->rx_count || !channel->tx_count)
                return -EINVAL;
@@ -551,6 +556,9 @@ static int nicvf_set_channels(struct net_device *dev,
        if (channel->tx_count > MAX_SND_QUEUES_PER_QS)
                return -EINVAL;
 
+       if (if_up)
+               nicvf_stop(dev);
+
        nic->qs->rq_cnt = channel->rx_count;
        nic->qs->sq_cnt = channel->tx_count;
        nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt);
@@ -559,11 +567,9 @@ static int nicvf_set_channels(struct net_device *dev,
        if (err)
                return err;
 
-       if (!netif_running(dev))
-               return err;
+       if (if_up)
+               nicvf_open(dev);
 
-       nicvf_stop(dev);
-       nicvf_open(dev);
        netdev_info(dev, "Setting num Tx rings to %d, Rx rings to %d success\n",
                    nic->qs->sq_cnt, nic->qs->rq_cnt);
 
index 8b119a035b7e2f547a9259ce35eb390ce09c4b90..3b90afb8c293254e999f76f3ebbfbd0108dd7022 100644 (file)
@@ -234,7 +234,7 @@ static void  nicvf_handle_mbx_intr(struct nicvf *nic)
                                    nic->duplex == DUPLEX_FULL ?
                                "Full duplex" : "Half duplex");
                        netif_carrier_on(nic->netdev);
-                       netif_tx_wake_all_queues(nic->netdev);
+                       netif_tx_start_all_queues(nic->netdev);
                } else {
                        netdev_info(nic->netdev, "%s: Link is Down\n",
                                    nic->netdev->name);
@@ -425,6 +425,7 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev,
        if (skb) {
                prefetch(skb);
                dev_consume_skb_any(skb);
+               sq->skbuff[cqe_tx->sqe_ptr] = (u64)NULL;
        }
 }
 
@@ -476,12 +477,13 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
 static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx,
                                 struct napi_struct *napi, int budget)
 {
-       int processed_cqe, work_done = 0;
+       int processed_cqe, work_done = 0, tx_done = 0;
        int cqe_count, cqe_head;
        struct nicvf *nic = netdev_priv(netdev);
        struct queue_set *qs = nic->qs;
        struct cmp_queue *cq = &qs->cq[cq_idx];
        struct cqe_rx_t *cq_desc;
+       struct netdev_queue *txq;
 
        spin_lock_bh(&cq->lock);
 loop:
@@ -496,8 +498,8 @@ loop:
        cqe_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, cq_idx) >> 9;
        cqe_head &= 0xFFFF;
 
-       netdev_dbg(nic->netdev, "%s cqe_count %d cqe_head %d\n",
-                  __func__, cqe_count, cqe_head);
+       netdev_dbg(nic->netdev, "%s CQ%d cqe_count %d cqe_head %d\n",
+                  __func__, cq_idx, cqe_count, cqe_head);
        while (processed_cqe < cqe_count) {
                /* Get the CQ descriptor */
                cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head);
@@ -511,8 +513,8 @@ loop:
                        break;
                }
 
-               netdev_dbg(nic->netdev, "cq_desc->cqe_type %d\n",
-                          cq_desc->cqe_type);
+               netdev_dbg(nic->netdev, "CQ%d cq_desc->cqe_type %d\n",
+                          cq_idx, cq_desc->cqe_type);
                switch (cq_desc->cqe_type) {
                case CQE_TYPE_RX:
                        nicvf_rcv_pkt_handler(netdev, napi, cq,
@@ -522,6 +524,7 @@ loop:
                case CQE_TYPE_SEND:
                        nicvf_snd_pkt_handler(netdev, cq,
                                              (void *)cq_desc, CQE_TYPE_SEND);
+                       tx_done++;
                break;
                case CQE_TYPE_INVALID:
                case CQE_TYPE_RX_SPLIT:
@@ -532,8 +535,9 @@ loop:
                }
                processed_cqe++;
        }
-       netdev_dbg(nic->netdev, "%s processed_cqe %d work_done %d budget %d\n",
-                  __func__, processed_cqe, work_done, budget);
+       netdev_dbg(nic->netdev,
+                  "%s CQ%d processed_cqe %d work_done %d budget %d\n",
+                  __func__, cq_idx, processed_cqe, work_done, budget);
 
        /* Ring doorbell to inform H/W to reuse processed CQEs */
        nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_DOOR,
@@ -543,6 +547,19 @@ loop:
                goto loop;
 
 done:
+       /* Wakeup TXQ if its stopped earlier due to SQ full */
+       if (tx_done) {
+               txq = netdev_get_tx_queue(netdev, cq_idx);
+               if (netif_tx_queue_stopped(txq)) {
+                       netif_tx_start_queue(txq);
+                       nic->drv_stats.txq_wake++;
+                       if (netif_msg_tx_err(nic))
+                               netdev_warn(netdev,
+                                           "%s: Transmit queue wakeup SQ%d\n",
+                                           netdev->name, cq_idx);
+               }
+       }
+
        spin_unlock_bh(&cq->lock);
        return work_done;
 }
@@ -554,15 +571,10 @@ static int nicvf_poll(struct napi_struct *napi, int budget)
        struct net_device *netdev = napi->dev;
        struct nicvf *nic = netdev_priv(netdev);
        struct nicvf_cq_poll *cq;
-       struct netdev_queue *txq;
 
        cq = container_of(napi, struct nicvf_cq_poll, napi);
        work_done = nicvf_cq_intr_handler(netdev, cq->cq_idx, napi, budget);
 
-       txq = netdev_get_tx_queue(netdev, cq->cq_idx);
-       if (netif_tx_queue_stopped(txq))
-               netif_tx_wake_queue(txq);
-
        if (work_done < budget) {
                /* Slow packet rate, exit polling */
                napi_complete(napi);
@@ -833,9 +845,9 @@ static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev)
                return NETDEV_TX_OK;
        }
 
-       if (!nicvf_sq_append_skb(nic, skb) && !netif_tx_queue_stopped(txq)) {
+       if (!netif_tx_queue_stopped(txq) && !nicvf_sq_append_skb(nic, skb)) {
                netif_tx_stop_queue(txq);
-               nic->drv_stats.tx_busy++;
+               nic->drv_stats.txq_stop++;
                if (netif_msg_tx_err(nic))
                        netdev_warn(netdev,
                                    "%s: Transmit ring full, stopping SQ%d\n",
@@ -859,7 +871,6 @@ int nicvf_stop(struct net_device *netdev)
        nicvf_send_msg_to_pf(nic, &mbx);
 
        netif_carrier_off(netdev);
-       netif_tx_disable(netdev);
 
        /* Disable RBDR & QS error interrupts */
        for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) {
@@ -894,6 +905,8 @@ int nicvf_stop(struct net_device *netdev)
                kfree(cq_poll);
        }
 
+       netif_tx_disable(netdev);
+
        /* Free resources */
        nicvf_config_data_transfer(nic, false);
 
@@ -988,6 +1001,9 @@ int nicvf_open(struct net_device *netdev)
        for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
                nicvf_enable_intr(nic, NICVF_INTR_RBDR, qidx);
 
+       nic->drv_stats.txq_stop = 0;
+       nic->drv_stats.txq_wake = 0;
+
        netif_carrier_on(netdev);
        netif_tx_start_all_queues(netdev);
 
@@ -1278,6 +1294,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        netdev->hw_features = netdev->features;
 
        netdev->netdev_ops = &nicvf_netdev_ops;
+       netdev->watchdog_timeo = NICVF_TX_TIMEOUT;
 
        INIT_WORK(&nic->reset_task, nicvf_reset_task);
 
@@ -1318,11 +1335,17 @@ static void nicvf_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
+static void nicvf_shutdown(struct pci_dev *pdev)
+{
+       nicvf_remove(pdev);
+}
+
 static struct pci_driver nicvf_driver = {
        .name = DRV_NAME,
        .id_table = nicvf_id_table,
        .probe = nicvf_probe,
        .remove = nicvf_remove,
+       .shutdown = nicvf_shutdown,
 };
 
 static int __init nicvf_init_module(void)
index d69d228d11a013b4cb709041e49472a9b3b34040..ca4240aa6d1567c044442c239c16f330bdd4f0f4 100644 (file)
@@ -103,9 +103,11 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, gfp_t gfp,
 
        /* Allocate a new page */
        if (!nic->rb_page) {
-               nic->rb_page = alloc_pages(gfp | __GFP_COMP, order);
+               nic->rb_page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN,
+                                          order);
                if (!nic->rb_page) {
-                       netdev_err(nic->netdev, "Failed to allocate new rcv buffer\n");
+                       netdev_err(nic->netdev,
+                                  "Failed to allocate new rcv buffer\n");
                        return -ENOMEM;
                }
                nic->rb_page_offset = 0;
@@ -382,7 +384,8 @@ static void nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq)
                return;
 
        if (sq->tso_hdrs)
-               dma_free_coherent(&nic->pdev->dev, sq->dmem.q_len,
+               dma_free_coherent(&nic->pdev->dev,
+                                 sq->dmem.q_len * TSO_HEADER_SIZE,
                                  sq->tso_hdrs, sq->tso_hdrs_phys);
 
        kfree(sq->skbuff);
@@ -863,10 +866,11 @@ void nicvf_sq_free_used_descs(struct net_device *netdev, struct snd_queue *sq,
                        continue;
                }
                skb = (struct sk_buff *)sq->skbuff[sq->head];
+               if (skb)
+                       dev_kfree_skb_any(skb);
                atomic64_add(1, (atomic64_t *)&netdev->stats.tx_packets);
                atomic64_add(hdr->tot_len,
                             (atomic64_t *)&netdev->stats.tx_bytes);
-               dev_kfree_skb_any(skb);
                nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
        }
 }
@@ -992,7 +996,7 @@ static inline void nicvf_sq_add_gather_subdesc(struct snd_queue *sq, int qentry,
 
        memset(gather, 0, SND_QUEUE_DESC_SIZE);
        gather->subdesc_type = SQ_DESC_TYPE_GATHER;
-       gather->ld_type = NIC_SEND_LD_TYPE_E_LDWB;
+       gather->ld_type = NIC_SEND_LD_TYPE_E_LDD;
        gather->size = size;
        gather->addr = data;
 }
@@ -1048,7 +1052,7 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
                }
                nicvf_sq_add_hdr_subdesc(sq, hdr_qentry,
                                         seg_subdescs - 1, skb, seg_len);
-               sq->skbuff[hdr_qentry] = 0;
+               sq->skbuff[hdr_qentry] = (u64)NULL;
                qentry = nicvf_get_nxt_sqentry(sq, qentry);
 
                desc_cnt += seg_subdescs;
@@ -1062,6 +1066,7 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
        /* Inform HW to xmit all TSO segments */
        nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR,
                              skb_get_queue_mapping(skb), desc_cnt);
+       nic->drv_stats.tx_tso++;
        return 1;
 }
 
index 8341bdf755d1dfa8a4d288c43d7037fccf5bb6ea..f0937b7bfe9f476d914f9eb28ad040125b9750d9 100644 (file)
@@ -62,7 +62,7 @@
 #define SND_QUEUE_CNT          8
 #define CMP_QUEUE_CNT          8 /* Max of RCV and SND qcount */
 
-#define SND_QSIZE              SND_QUEUE_SIZE4
+#define SND_QSIZE              SND_QUEUE_SIZE2
 #define SND_QUEUE_LEN          (1ULL << (SND_QSIZE + 10))
 #define MAX_SND_QUEUE_LEN      (1ULL << (SND_QUEUE_SIZE6 + 10))
 #define SND_QUEUE_THRESH       2ULL
 /* Since timestamp not enabled, otherwise 2 */
 #define MAX_CQE_PER_PKT_XMIT           1
 
-#define CMP_QSIZE              CMP_QUEUE_SIZE4
+/* Keep CQ and SQ sizes same, if timestamping
+ * is enabled this equation will change.
+ */
+#define CMP_QSIZE              CMP_QUEUE_SIZE2
 #define CMP_QUEUE_LEN          (1ULL << (CMP_QSIZE + 10))
 #define CMP_QUEUE_CQE_THRESH   0
 #define CMP_QUEUE_TIMER_THRESH 220 /* 10usec */
 
 #define MAX_CQES_FOR_TX                ((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) * \
                                 MAX_CQE_PER_PKT_XMIT)
-#define RQ_CQ_DROP             ((CMP_QUEUE_LEN - MAX_CQES_FOR_TX) / 256)
+/* Calculate number of CQEs to reserve for all SQEs.
+ * Its 1/256th level of CQ size.
+ * '+ 1' to account for pipelining
+ */
+#define RQ_CQ_DROP             ((256 / (CMP_QUEUE_LEN / \
+                                (CMP_QUEUE_LEN - MAX_CQES_FOR_TX))) + 1)
 
 /* Descriptor size in bytes */
 #define SND_QUEUE_DESC_SIZE    16
index 633ec05dfe0578b71825bf409df24371f58a776c..b961a89dc6264555553ee94484478b5dca9822dc 100644 (file)
@@ -673,7 +673,10 @@ static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid)
        bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cmrx_cfg);
        bgx_flush_dmac_addrs(bgx, lmacid);
 
-       if (lmac->phydev)
+       if ((bgx->lmac_type != BGX_MODE_XFI) &&
+           (bgx->lmac_type != BGX_MODE_XLAUI) &&
+           (bgx->lmac_type != BGX_MODE_40G_KR) &&
+           (bgx->lmac_type != BGX_MODE_10G_KR) && lmac->phydev)
                phy_disconnect(lmac->phydev);
 
        lmac->phydev = NULL;
index a11485fbb33f2b7bcd6c973324ea41601dbaf575..c3c7db41819dfad26b521008c6c70148711ee019 100644 (file)
@@ -2332,10 +2332,11 @@ int t4_setup_debugfs(struct adapter *adap)
                                        EXT_MEM1_SIZE_G(size));
                }
        } else {
-               if (i & EXT_MEM_ENABLE_F)
+               if (i & EXT_MEM_ENABLE_F) {
                        size = t4_read_reg(adap, MA_EXT_MEMORY_BAR_A);
                        add_debugfs_mem(adap, "mc", MEM_MC,
                                        EXT_MEM_SIZE_G(size));
+               }
        }
 
        de = debugfs_create_file_size("flash", S_IRUSR, adap->debugfs_root, adap,
index 2716e6f30d9a0949633b40dc9864196c7465fa3a..00e3a6b6b82254269aa7e0bf5d165f13d358594f 100644 (file)
@@ -620,6 +620,11 @@ enum be_if_flags {
                                         BE_IF_FLAGS_VLAN_PROMISCUOUS |\
                                         BE_IF_FLAGS_MCAST_PROMISCUOUS)
 
+#define BE_IF_EN_FLAGS (BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |\
+                       BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_UNTAGGED)
+
+#define BE_IF_ALL_FILT_FLAGS   (BE_IF_EN_FLAGS | BE_IF_FLAGS_ALL_PROMISCUOUS)
+
 /* An RX interface is an object with one or more MAC addresses and
  * filtering capabilities. */
 struct be_cmd_req_if_create {
index 6f642426308c67399eac3abdb20ae6160ce41d2a..c28e3bfdccd75def6aef2522a9aaf827e0d45828 100644 (file)
@@ -273,6 +273,10 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
        if (ether_addr_equal(addr->sa_data, netdev->dev_addr))
                return 0;
 
+       /* if device is not running, copy MAC to netdev->dev_addr */
+       if (!netif_running(netdev))
+               goto done;
+
        /* The PMAC_ADD cmd may fail if the VF doesn't have FILTMGMT
         * privilege or if PF did not provision the new MAC address.
         * On BE3, this cmd will always fail if the VF doesn't have the
@@ -307,9 +311,9 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
                status = -EPERM;
                goto err;
        }
-
-       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-       dev_info(dev, "MAC address changed to %pM\n", mac);
+done:
+       ether_addr_copy(netdev->dev_addr, addr->sa_data);
+       dev_info(dev, "MAC address changed to %pM\n", addr->sa_data);
        return 0;
 err:
        dev_warn(dev, "MAC address change to %pM failed\n", addr->sa_data);
@@ -2447,10 +2451,24 @@ static void be_eq_clean(struct be_eq_obj *eqo)
        be_eq_notify(eqo->adapter, eqo->q.id, false, true, num, 0);
 }
 
-static void be_rx_cq_clean(struct be_rx_obj *rxo)
+/* Free posted rx buffers that were not used */
+static void be_rxq_clean(struct be_rx_obj *rxo)
 {
-       struct be_rx_page_info *page_info;
        struct be_queue_info *rxq = &rxo->q;
+       struct be_rx_page_info *page_info;
+
+       while (atomic_read(&rxq->used) > 0) {
+               page_info = get_rx_page_info(rxo);
+               put_page(page_info->page);
+               memset(page_info, 0, sizeof(*page_info));
+       }
+       BUG_ON(atomic_read(&rxq->used));
+       rxq->tail = 0;
+       rxq->head = 0;
+}
+
+static void be_rx_cq_clean(struct be_rx_obj *rxo)
+{
        struct be_queue_info *rx_cq = &rxo->cq;
        struct be_rx_compl_info *rxcp;
        struct be_adapter *adapter = rxo->adapter;
@@ -2487,16 +2505,6 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
 
        /* After cleanup, leave the CQ in unarmed state */
        be_cq_notify(adapter, rx_cq->id, false, 0);
-
-       /* Then free posted rx buffers that were not used */
-       while (atomic_read(&rxq->used) > 0) {
-               page_info = get_rx_page_info(rxo);
-               put_page(page_info->page);
-               memset(page_info, 0, sizeof(*page_info));
-       }
-       BUG_ON(atomic_read(&rxq->used));
-       rxq->tail = 0;
-       rxq->head = 0;
 }
 
 static void be_tx_compl_clean(struct be_adapter *adapter)
@@ -2576,8 +2584,8 @@ static void be_evt_queues_destroy(struct be_adapter *adapter)
                        be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ);
                        napi_hash_del(&eqo->napi);
                        netif_napi_del(&eqo->napi);
+                       free_cpumask_var(eqo->affinity_mask);
                }
-               free_cpumask_var(eqo->affinity_mask);
                be_queue_free(adapter, &eqo->q);
        }
 }
@@ -2594,13 +2602,7 @@ static int be_evt_queues_create(struct be_adapter *adapter)
 
        for_all_evt_queues(adapter, eqo, i) {
                int numa_node = dev_to_node(&adapter->pdev->dev);
-               if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL))
-                       return -ENOMEM;
-               cpumask_set_cpu(cpumask_local_spread(i, numa_node),
-                               eqo->affinity_mask);
-               netif_napi_add(adapter->netdev, &eqo->napi, be_poll,
-                              BE_NAPI_WEIGHT);
-               napi_hash_add(&eqo->napi);
+
                aic = &adapter->aic_obj[i];
                eqo->adapter = adapter;
                eqo->idx = i;
@@ -2616,6 +2618,14 @@ static int be_evt_queues_create(struct be_adapter *adapter)
                rc = be_cmd_eq_create(adapter, eqo);
                if (rc)
                        return rc;
+
+               if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL))
+                       return -ENOMEM;
+               cpumask_set_cpu(cpumask_local_spread(i, numa_node),
+                               eqo->affinity_mask);
+               netif_napi_add(adapter->netdev, &eqo->napi, be_poll,
+                              BE_NAPI_WEIGHT);
+               napi_hash_add(&eqo->napi);
        }
        return 0;
 }
@@ -3354,13 +3364,54 @@ static void be_rx_qs_destroy(struct be_adapter *adapter)
        for_all_rx_queues(adapter, rxo, i) {
                q = &rxo->q;
                if (q->created) {
+                       /* If RXQs are destroyed while in an "out of buffer"
+                        * state, there is a possibility of an HW stall on
+                        * Lancer. So, post 64 buffers to each queue to relieve
+                        * the "out of buffer" condition.
+                        * Make sure there's space in the RXQ before posting.
+                        */
+                       if (lancer_chip(adapter)) {
+                               be_rx_cq_clean(rxo);
+                               if (atomic_read(&q->used) == 0)
+                                       be_post_rx_frags(rxo, GFP_KERNEL,
+                                                        MAX_RX_POST);
+                       }
+
                        be_cmd_rxq_destroy(adapter, q);
                        be_rx_cq_clean(rxo);
+                       be_rxq_clean(rxo);
                }
                be_queue_free(adapter, q);
        }
 }
 
+static void be_disable_if_filters(struct be_adapter *adapter)
+{
+       be_cmd_pmac_del(adapter, adapter->if_handle,
+                       adapter->pmac_id[0], 0);
+
+       be_clear_uc_list(adapter);
+
+       /* The IFACE flags are enabled in the open path and cleared
+        * in the close path. When a VF gets detached from the host and
+        * assigned to a VM the following happens:
+        *      - VF's IFACE flags get cleared in the detach path
+        *      - IFACE create is issued by the VF in the attach path
+        * Due to a bug in the BE3/Skyhawk-R FW
+        * (Lancer FW doesn't have the bug), the IFACE capability flags
+        * specified along with the IFACE create cmd issued by a VF are not
+        * honoured by FW.  As a consequence, if a *new* driver
+        * (that enables/disables IFACE flags in open/close)
+        * is loaded in the host and an *old* driver is * used by a VM/VF,
+        * the IFACE gets created *without* the needed flags.
+        * To avoid this, disable RX-filter flags only for Lancer.
+        */
+       if (lancer_chip(adapter)) {
+               be_cmd_rx_filter(adapter, BE_IF_ALL_FILT_FLAGS, OFF);
+               adapter->if_flags &= ~BE_IF_ALL_FILT_FLAGS;
+       }
+}
+
 static int be_close(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -3373,6 +3424,8 @@ static int be_close(struct net_device *netdev)
        if (!(adapter->flags & BE_FLAGS_SETUP_DONE))
                return 0;
 
+       be_disable_if_filters(adapter);
+
        be_roce_dev_close(adapter);
 
        if (adapter->flags & BE_FLAGS_NAPI_ENABLED) {
@@ -3392,7 +3445,6 @@ static int be_close(struct net_device *netdev)
        be_tx_compl_clean(adapter);
 
        be_rx_qs_destroy(adapter);
-       be_clear_uc_list(adapter);
 
        for_all_evt_queues(adapter, eqo, i) {
                if (msix_enabled(adapter))
@@ -3477,6 +3529,31 @@ static int be_rx_qs_create(struct be_adapter *adapter)
        return 0;
 }
 
+static int be_enable_if_filters(struct be_adapter *adapter)
+{
+       int status;
+
+       status = be_cmd_rx_filter(adapter, BE_IF_EN_FLAGS, ON);
+       if (status)
+               return status;
+
+       /* For BE3 VFs, the PF programs the initial MAC address */
+       if (!(BEx_chip(adapter) && be_virtfn(adapter))) {
+               status = be_cmd_pmac_add(adapter, adapter->netdev->dev_addr,
+                                        adapter->if_handle,
+                                        &adapter->pmac_id[0], 0);
+               if (status)
+                       return status;
+       }
+
+       if (adapter->vlans_added)
+               be_vid_config(adapter);
+
+       be_set_rx_mode(adapter->netdev);
+
+       return 0;
+}
+
 static int be_open(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -3490,6 +3567,10 @@ static int be_open(struct net_device *netdev)
        if (status)
                goto err;
 
+       status = be_enable_if_filters(adapter);
+       if (status)
+               goto err;
+
        status = be_irq_register(adapter);
        if (status)
                goto err;
@@ -3686,16 +3767,6 @@ static void be_cancel_err_detection(struct be_adapter *adapter)
        }
 }
 
-static void be_mac_clear(struct be_adapter *adapter)
-{
-       if (adapter->pmac_id) {
-               be_cmd_pmac_del(adapter, adapter->if_handle,
-                               adapter->pmac_id[0], 0);
-               kfree(adapter->pmac_id);
-               adapter->pmac_id = NULL;
-       }
-}
-
 #ifdef CONFIG_BE2NET_VXLAN
 static void be_disable_vxlan_offloads(struct be_adapter *adapter)
 {
@@ -3770,8 +3841,8 @@ static int be_clear(struct be_adapter *adapter)
 #ifdef CONFIG_BE2NET_VXLAN
        be_disable_vxlan_offloads(adapter);
 #endif
-       /* delete the primary mac along with the uc-mac list */
-       be_mac_clear(adapter);
+       kfree(adapter->pmac_id);
+       adapter->pmac_id = NULL;
 
        be_cmd_if_destroy(adapter, adapter->if_handle,  0);
 
@@ -3782,25 +3853,11 @@ static int be_clear(struct be_adapter *adapter)
        return 0;
 }
 
-static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
-                       u32 cap_flags, u32 vf)
-{
-       u32 en_flags;
-
-       en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
-                  BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
-                  BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS;
-
-       en_flags &= cap_flags;
-
-       return be_cmd_if_create(adapter, cap_flags, en_flags, if_handle, vf);
-}
-
 static int be_vfs_if_create(struct be_adapter *adapter)
 {
        struct be_resources res = {0};
+       u32 cap_flags, en_flags, vf;
        struct be_vf_cfg *vf_cfg;
-       u32 cap_flags, vf;
        int status;
 
        /* If a FW profile exists, then cap_flags are updated */
@@ -3821,8 +3878,12 @@ static int be_vfs_if_create(struct be_adapter *adapter)
                        }
                }
 
-               status = be_if_create(adapter, &vf_cfg->if_handle,
-                                     cap_flags, vf + 1);
+               en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
+                                       BE_IF_FLAGS_BROADCAST |
+                                       BE_IF_FLAGS_MULTICAST |
+                                       BE_IF_FLAGS_PASS_L3L4_ERRORS);
+               status = be_cmd_if_create(adapter, cap_flags, en_flags,
+                                         &vf_cfg->if_handle, vf + 1);
                if (status)
                        return status;
        }
@@ -4194,15 +4255,8 @@ static int be_mac_setup(struct be_adapter *adapter)
 
                memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
                memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
-       } else {
-               /* Maybe the HW was reset; dev_addr must be re-programmed */
-               memcpy(mac, adapter->netdev->dev_addr, ETH_ALEN);
        }
 
-       /* For BE3-R VFs, the PF programs the initial MAC address */
-       if (!(BEx_chip(adapter) && be_virtfn(adapter)))
-               be_cmd_pmac_add(adapter, mac, adapter->if_handle,
-                               &adapter->pmac_id[0], 0);
        return 0;
 }
 
@@ -4342,6 +4396,7 @@ static int be_func_init(struct be_adapter *adapter)
 static int be_setup(struct be_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
+       u32 en_flags;
        int status;
 
        status = be_func_init(adapter);
@@ -4364,8 +4419,11 @@ static int be_setup(struct be_adapter *adapter)
        if (status)
                goto err;
 
-       status = be_if_create(adapter, &adapter->if_handle,
-                             be_if_cap_flags(adapter), 0);
+       /* will enable all the needed filter flags in be_open() */
+       en_flags = BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS;
+       en_flags = en_flags & be_if_cap_flags(adapter);
+       status = be_cmd_if_create(adapter, be_if_cap_flags(adapter), en_flags,
+                                 &adapter->if_handle, 0);
        if (status)
                goto err;
 
@@ -4391,11 +4449,6 @@ static int be_setup(struct be_adapter *adapter)
                dev_err(dev, "Please upgrade firmware to version >= 4.0\n");
        }
 
-       if (adapter->vlans_added)
-               be_vid_config(adapter);
-
-       be_set_rx_mode(adapter->netdev);
-
        status = be_cmd_set_flow_control(adapter, adapter->tx_fc,
                                         adapter->rx_fc);
        if (status)
index 1eee73cccdf58deba85c810399930ffa55dfa03c..99d33e2d35e6c2c219fbd06f34546619a01a586d 100644 (file)
@@ -562,6 +562,7 @@ struct fec_enet_private {
 };
 
 void fec_ptp_init(struct platform_device *pdev);
+void fec_ptp_stop(struct platform_device *pdev);
 void fec_ptp_start_cyclecounter(struct net_device *ndev);
 int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
 int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
index 42e20e5385acb553b528ee8a6b275791e9ad1b44..271bb5862346ede352473f0837fb76e0a5ac7163 100644 (file)
@@ -3142,8 +3142,8 @@ static int fec_enet_init(struct net_device *ndev)
                        fep->bufdesc_size;
 
        /* Allocate memory for buffer descriptors. */
-       cbd_base = dma_alloc_coherent(NULL, bd_size, &bd_dma,
-                                     GFP_KERNEL);
+       cbd_base = dmam_alloc_coherent(&fep->pdev->dev, bd_size, &bd_dma,
+                                      GFP_KERNEL);
        if (!cbd_base) {
                return -ENOMEM;
        }
@@ -3431,6 +3431,12 @@ fec_probe(struct platform_device *pdev)
                fep->reg_phy = NULL;
        }
 
+       pm_runtime_set_autosuspend_delay(&pdev->dev, FEC_MDIO_PM_TIMEOUT);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_get_noresume(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
        fec_reset_phy(pdev);
 
        if (fep->bufdesc_ex)
@@ -3465,8 +3471,6 @@ fec_probe(struct platform_device *pdev)
        netif_carrier_off(ndev);
        fec_enet_clk_enable(ndev, false);
        pinctrl_pm_select_sleep_state(&pdev->dev);
-       pm_runtime_set_active(&pdev->dev);
-       pm_runtime_enable(&pdev->dev);
 
        ret = register_netdev(ndev);
        if (ret)
@@ -3481,8 +3485,6 @@ fec_probe(struct platform_device *pdev)
        fep->rx_copybreak = COPYBREAK_DEFAULT;
        INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work);
 
-       pm_runtime_set_autosuspend_delay(&pdev->dev, FEC_MDIO_PM_TIMEOUT);
-       pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_mark_last_busy(&pdev->dev);
        pm_runtime_put_autosuspend(&pdev->dev);
 
@@ -3493,6 +3495,7 @@ failed_register:
 failed_mii_init:
 failed_irq:
 failed_init:
+       fec_ptp_stop(pdev);
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
 failed_regulator:
@@ -3514,14 +3517,12 @@ fec_drv_remove(struct platform_device *pdev)
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
 
-       cancel_delayed_work_sync(&fep->time_keep);
        cancel_work_sync(&fep->tx_timeout_work);
+       fec_ptp_stop(pdev);
        unregister_netdev(ndev);
        fec_enet_mii_remove(fep);
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
-       if (fep->ptp_clock)
-               ptp_clock_unregister(fep->ptp_clock);
        of_node_put(fep->phy_node);
        free_netdev(ndev);
 
index a15663ad7f5e98c64a1f6e0912163bee578c938b..f457a23d0bfbd4149332d9bb93506891670ca36d 100644 (file)
@@ -604,6 +604,16 @@ void fec_ptp_init(struct platform_device *pdev)
        schedule_delayed_work(&fep->time_keep, HZ);
 }
 
+void fec_ptp_stop(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct fec_enet_private *fep = netdev_priv(ndev);
+
+       cancel_delayed_work_sync(&fep->time_keep);
+       if (fep->ptp_clock)
+               ptp_clock_unregister(fep->ptp_clock);
+}
+
 /**
  * fec_ptp_check_pps_event
  * @fep: the fec_enet_private structure handle
index 56316db6c5a674fd1d17ef20e8db3747950cf71e..cf8e54652df95266e24a5d6d64ed67c00336f67b 100644 (file)
@@ -586,7 +586,8 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        frag = skb_shinfo(skb)->frags;
        while (nr_frags) {
                CBDC_SC(bdp,
-                       BD_ENET_TX_STATS | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+                       BD_ENET_TX_STATS | BD_ENET_TX_INTR | BD_ENET_TX_LAST |
+                       BD_ENET_TX_TC);
                CBDS_SC(bdp, BD_ENET_TX_READY);
 
                if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)
index b34214e2df5f6e55bdbb29e6a8016c139e74345c..016743e355de31984d57904e802d69e6703ea5e4 100644 (file)
@@ -110,7 +110,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
 }
 
 #define FEC_NAPI_RX_EVENT_MSK  (FEC_ENET_RXF | FEC_ENET_RXB)
-#define FEC_NAPI_TX_EVENT_MSK  (FEC_ENET_TXF | FEC_ENET_TXB)
+#define FEC_NAPI_TX_EVENT_MSK  (FEC_ENET_TXF)
 #define FEC_RX_EVENT           (FEC_ENET_RXF)
 #define FEC_TX_EVENT           (FEC_ENET_TXF)
 #define FEC_ERR_EVENT_MSK      (FEC_ENET_HBERR | FEC_ENET_BABR | \
index ff875028fdff5e1723c618f721658971cd051603..2b7610f341b09f4ff293f9916235030487fb2a80 100644 (file)
@@ -565,22 +565,6 @@ static void gfar_ints_enable(struct gfar_private *priv)
        }
 }
 
-static void lock_tx_qs(struct gfar_private *priv)
-{
-       int i;
-
-       for (i = 0; i < priv->num_tx_queues; i++)
-               spin_lock(&priv->tx_queue[i]->txlock);
-}
-
-static void unlock_tx_qs(struct gfar_private *priv)
-{
-       int i;
-
-       for (i = 0; i < priv->num_tx_queues; i++)
-               spin_unlock(&priv->tx_queue[i]->txlock);
-}
-
 static int gfar_alloc_tx_queues(struct gfar_private *priv)
 {
        int i;
@@ -1376,7 +1360,6 @@ static int gfar_probe(struct platform_device *ofdev)
        priv->dev = &ofdev->dev;
        SET_NETDEV_DEV(dev, &ofdev->dev);
 
-       spin_lock_init(&priv->bflock);
        INIT_WORK(&priv->reset_task, gfar_reset_task);
 
        platform_set_drvdata(ofdev, priv);
@@ -1470,9 +1453,8 @@ static int gfar_probe(struct platform_device *ofdev)
                goto register_fail;
        }
 
-       device_init_wakeup(&dev->dev,
-                          priv->device_flags &
-                          FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+       device_set_wakeup_capable(&dev->dev, priv->device_flags &
+                                 FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
        /* fill out IRQ number and name fields */
        for (i = 0; i < priv->num_grps; i++) {
@@ -1540,48 +1522,37 @@ static int gfar_suspend(struct device *dev)
        struct gfar_private *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->ndev;
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned long flags;
        u32 tempval;
-
        int magic_packet = priv->wol_en &&
                           (priv->device_flags &
                            FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
+       if (!netif_running(ndev))
+               return 0;
+
+       disable_napi(priv);
+       netif_tx_lock(ndev);
        netif_device_detach(ndev);
+       netif_tx_unlock(ndev);
 
-       if (netif_running(ndev)) {
+       gfar_halt(priv);
 
-               local_irq_save(flags);
-               lock_tx_qs(priv);
+       if (magic_packet) {
+               /* Enable interrupt on Magic Packet */
+               gfar_write(&regs->imask, IMASK_MAG);
 
-               gfar_halt_nodisable(priv);
+               /* Enable Magic Packet mode */
+               tempval = gfar_read(&regs->maccfg2);
+               tempval |= MACCFG2_MPEN;
+               gfar_write(&regs->maccfg2, tempval);
 
-               /* Disable Tx, and Rx if wake-on-LAN is disabled. */
+               /* re-enable the Rx block */
                tempval = gfar_read(&regs->maccfg1);
-
-               tempval &= ~MACCFG1_TX_EN;
-
-               if (!magic_packet)
-                       tempval &= ~MACCFG1_RX_EN;
-
+               tempval |= MACCFG1_RX_EN;
                gfar_write(&regs->maccfg1, tempval);
 
-               unlock_tx_qs(priv);
-               local_irq_restore(flags);
-
-               disable_napi(priv);
-
-               if (magic_packet) {
-                       /* Enable interrupt on Magic Packet */
-                       gfar_write(&regs->imask, IMASK_MAG);
-
-                       /* Enable Magic Packet mode */
-                       tempval = gfar_read(&regs->maccfg2);
-                       tempval |= MACCFG2_MPEN;
-                       gfar_write(&regs->maccfg2, tempval);
-               } else {
-                       phy_stop(priv->phydev);
-               }
+       } else {
+               phy_stop(priv->phydev);
        }
 
        return 0;
@@ -1592,37 +1563,26 @@ static int gfar_resume(struct device *dev)
        struct gfar_private *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->ndev;
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned long flags;
        u32 tempval;
        int magic_packet = priv->wol_en &&
                           (priv->device_flags &
                            FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
-       if (!netif_running(ndev)) {
-               netif_device_attach(ndev);
+       if (!netif_running(ndev))
                return 0;
-       }
 
-       if (!magic_packet && priv->phydev)
+       if (magic_packet) {
+               /* Disable Magic Packet mode */
+               tempval = gfar_read(&regs->maccfg2);
+               tempval &= ~MACCFG2_MPEN;
+               gfar_write(&regs->maccfg2, tempval);
+       } else {
                phy_start(priv->phydev);
-
-       /* Disable Magic Packet mode, in case something
-        * else woke us up.
-        */
-       local_irq_save(flags);
-       lock_tx_qs(priv);
-
-       tempval = gfar_read(&regs->maccfg2);
-       tempval &= ~MACCFG2_MPEN;
-       gfar_write(&regs->maccfg2, tempval);
+       }
 
        gfar_start(priv);
 
-       unlock_tx_qs(priv);
-       local_irq_restore(flags);
-
        netif_device_attach(ndev);
-
        enable_napi(priv);
 
        return 0;
@@ -2045,7 +2005,8 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
                /* Install our interrupt handlers for Error,
                 * Transmit, and Receive
                 */
-               err = request_irq(gfar_irq(grp, ER)->irq, gfar_error, 0,
+               err = request_irq(gfar_irq(grp, ER)->irq, gfar_error,
+                                 IRQF_NO_SUSPEND,
                                  gfar_irq(grp, ER)->name, grp);
                if (err < 0) {
                        netif_err(priv, intr, dev, "Can't get IRQ %d\n",
@@ -2068,7 +2029,8 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
                        goto rx_irq_fail;
                }
        } else {
-               err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0,
+               err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt,
+                                 IRQF_NO_SUSPEND,
                                  gfar_irq(grp, TX)->name, grp);
                if (err < 0) {
                        netif_err(priv, intr, dev, "Can't get IRQ %d\n",
@@ -2169,8 +2131,6 @@ static int gfar_enet_open(struct net_device *dev)
        if (err)
                return err;
 
-       device_set_wakeup_enable(&dev->dev, priv->wol_en);
-
        return err;
 }
 
index daa1d37de6427b93a756843074c5d2e5c1961467..5545e41033686e3d7443811e2ec1caa2da2f5be4 100644 (file)
@@ -1145,9 +1145,6 @@ struct gfar_private {
        int oldduplex;
        int oldlink;
 
-       /* Bitfield update lock */
-       spinlock_t bflock;
-
        uint32_t msg_enable;
 
        struct work_struct reset_task;
index fda12fb32ec77a8538a0f1d1370d2e653c91856c..5b90fcf96265aec4a6daa1f28135ef2fa06a0752 100644 (file)
@@ -653,7 +653,6 @@ static void gfar_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct gfar_private *priv = netdev_priv(dev);
-       unsigned long flags;
 
        if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
            wol->wolopts != 0)
@@ -664,9 +663,7 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 
        device_set_wakeup_enable(&dev->dev, wol->wolopts & WAKE_MAGIC);
 
-       spin_lock_irqsave(&priv->bflock, flags);
-       priv->wol_en =  !!device_may_wakeup(&dev->dev);
-       spin_unlock_irqrestore(&priv->bflock, flags);
+       priv->wol_en = !!device_may_wakeup(&dev->dev);
 
        return 0;
 }
@@ -903,27 +900,6 @@ static int gfar_check_filer_hardware(struct gfar_private *priv)
        return 0;
 }
 
-static int gfar_comp_asc(const void *a, const void *b)
-{
-       return memcmp(a, b, 4);
-}
-
-static int gfar_comp_desc(const void *a, const void *b)
-{
-       return -memcmp(a, b, 4);
-}
-
-static void gfar_swap(void *a, void *b, int size)
-{
-       u32 *_a = a;
-       u32 *_b = b;
-
-       swap(_a[0], _b[0]);
-       swap(_a[1], _b[1]);
-       swap(_a[2], _b[2]);
-       swap(_a[3], _b[3]);
-}
-
 /* Write a mask to filer cache */
 static void gfar_set_mask(u32 mask, struct filer_table *tab)
 {
@@ -1273,310 +1249,6 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule,
        return 0;
 }
 
-/* Copy size filer entries */
-static void gfar_copy_filer_entries(struct gfar_filer_entry dst[0],
-                                   struct gfar_filer_entry src[0], s32 size)
-{
-       while (size > 0) {
-               size--;
-               dst[size].ctrl = src[size].ctrl;
-               dst[size].prop = src[size].prop;
-       }
-}
-
-/* Delete the contents of the filer-table between start and end
- * and collapse them
- */
-static int gfar_trim_filer_entries(u32 begin, u32 end, struct filer_table *tab)
-{
-       int length;
-
-       if (end > MAX_FILER_CACHE_IDX || end < begin)
-               return -EINVAL;
-
-       end++;
-       length = end - begin;
-
-       /* Copy */
-       while (end < tab->index) {
-               tab->fe[begin].ctrl = tab->fe[end].ctrl;
-               tab->fe[begin++].prop = tab->fe[end++].prop;
-
-       }
-       /* Fill up with don't cares */
-       while (begin < tab->index) {
-               tab->fe[begin].ctrl = 0x60;
-               tab->fe[begin].prop = 0xFFFFFFFF;
-               begin++;
-       }
-
-       tab->index -= length;
-       return 0;
-}
-
-/* Make space on the wanted location */
-static int gfar_expand_filer_entries(u32 begin, u32 length,
-                                    struct filer_table *tab)
-{
-       if (length == 0 || length + tab->index > MAX_FILER_CACHE_IDX ||
-           begin > MAX_FILER_CACHE_IDX)
-               return -EINVAL;
-
-       gfar_copy_filer_entries(&(tab->fe[begin + length]), &(tab->fe[begin]),
-                               tab->index - length + 1);
-
-       tab->index += length;
-       return 0;
-}
-
-static int gfar_get_next_cluster_start(int start, struct filer_table *tab)
-{
-       for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1);
-            start++) {
-               if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE)) ==
-                   (RQFCR_AND | RQFCR_CLE))
-                       return start;
-       }
-       return -1;
-}
-
-static int gfar_get_next_cluster_end(int start, struct filer_table *tab)
-{
-       for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1);
-            start++) {
-               if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE)) ==
-                   (RQFCR_CLE))
-                       return start;
-       }
-       return -1;
-}
-
-/* Uses hardwares clustering option to reduce
- * the number of filer table entries
- */
-static void gfar_cluster_filer(struct filer_table *tab)
-{
-       s32 i = -1, j, iend, jend;
-
-       while ((i = gfar_get_next_cluster_start(++i, tab)) != -1) {
-               j = i;
-               while ((j = gfar_get_next_cluster_start(++j, tab)) != -1) {
-                       /* The cluster entries self and the previous one
-                        * (a mask) must be identical!
-                        */
-                       if (tab->fe[i].ctrl != tab->fe[j].ctrl)
-                               break;
-                       if (tab->fe[i].prop != tab->fe[j].prop)
-                               break;
-                       if (tab->fe[i - 1].ctrl != tab->fe[j - 1].ctrl)
-                               break;
-                       if (tab->fe[i - 1].prop != tab->fe[j - 1].prop)
-                               break;
-                       iend = gfar_get_next_cluster_end(i, tab);
-                       jend = gfar_get_next_cluster_end(j, tab);
-                       if (jend == -1 || iend == -1)
-                               break;
-
-                       /* First we make some free space, where our cluster
-                        * element should be. Then we copy it there and finally
-                        * delete in from its old location.
-                        */
-                       if (gfar_expand_filer_entries(iend, (jend - j), tab) ==
-                           -EINVAL)
-                               break;
-
-                       gfar_copy_filer_entries(&(tab->fe[iend + 1]),
-                                               &(tab->fe[jend + 1]), jend - j);
-
-                       if (gfar_trim_filer_entries(jend - 1,
-                                                   jend + (jend - j),
-                                                   tab) == -EINVAL)
-                               return;
-
-                       /* Mask out cluster bit */
-                       tab->fe[iend].ctrl &= ~(RQFCR_CLE);
-               }
-       }
-}
-
-/* Swaps the masked bits of a1<>a2 and b1<>b2 */
-static void gfar_swap_bits(struct gfar_filer_entry *a1,
-                          struct gfar_filer_entry *a2,
-                          struct gfar_filer_entry *b1,
-                          struct gfar_filer_entry *b2, u32 mask)
-{
-       u32 temp[4];
-       temp[0] = a1->ctrl & mask;
-       temp[1] = a2->ctrl & mask;
-       temp[2] = b1->ctrl & mask;
-       temp[3] = b2->ctrl & mask;
-
-       a1->ctrl &= ~mask;
-       a2->ctrl &= ~mask;
-       b1->ctrl &= ~mask;
-       b2->ctrl &= ~mask;
-
-       a1->ctrl |= temp[1];
-       a2->ctrl |= temp[0];
-       b1->ctrl |= temp[3];
-       b2->ctrl |= temp[2];
-}
-
-/* Generate a list consisting of masks values with their start and
- * end of validity and block as indicator for parts belonging
- * together (glued by ANDs) in mask_table
- */
-static u32 gfar_generate_mask_table(struct gfar_mask_entry *mask_table,
-                                   struct filer_table *tab)
-{
-       u32 i, and_index = 0, block_index = 1;
-
-       for (i = 0; i < tab->index; i++) {
-
-               /* LSByte of control = 0 sets a mask */
-               if (!(tab->fe[i].ctrl & 0xF)) {
-                       mask_table[and_index].mask = tab->fe[i].prop;
-                       mask_table[and_index].start = i;
-                       mask_table[and_index].block = block_index;
-                       if (and_index >= 1)
-                               mask_table[and_index - 1].end = i - 1;
-                       and_index++;
-               }
-               /* cluster starts and ends will be separated because they should
-                * hold their position
-                */
-               if (tab->fe[i].ctrl & RQFCR_CLE)
-                       block_index++;
-               /* A not set AND indicates the end of a depended block */
-               if (!(tab->fe[i].ctrl & RQFCR_AND))
-                       block_index++;
-       }
-
-       mask_table[and_index - 1].end = i - 1;
-
-       return and_index;
-}
-
-/* Sorts the entries of mask_table by the values of the masks.
- * Important: The 0xFF80 flags of the first and last entry of a
- * block must hold their position (which queue, CLusterEnable, ReJEct,
- * AND)
- */
-static void gfar_sort_mask_table(struct gfar_mask_entry *mask_table,
-                                struct filer_table *temp_table, u32 and_index)
-{
-       /* Pointer to compare function (_asc or _desc) */
-       int (*gfar_comp)(const void *, const void *);
-
-       u32 i, size = 0, start = 0, prev = 1;
-       u32 old_first, old_last, new_first, new_last;
-
-       gfar_comp = &gfar_comp_desc;
-
-       for (i = 0; i < and_index; i++) {
-               if (prev != mask_table[i].block) {
-                       old_first = mask_table[start].start + 1;
-                       old_last = mask_table[i - 1].end;
-                       sort(mask_table + start, size,
-                            sizeof(struct gfar_mask_entry),
-                            gfar_comp, &gfar_swap);
-
-                       /* Toggle order for every block. This makes the
-                        * thing more efficient!
-                        */
-                       if (gfar_comp == gfar_comp_desc)
-                               gfar_comp = &gfar_comp_asc;
-                       else
-                               gfar_comp = &gfar_comp_desc;
-
-                       new_first = mask_table[start].start + 1;
-                       new_last = mask_table[i - 1].end;
-
-                       gfar_swap_bits(&temp_table->fe[new_first],
-                                      &temp_table->fe[old_first],
-                                      &temp_table->fe[new_last],
-                                      &temp_table->fe[old_last],
-                                      RQFCR_QUEUE | RQFCR_CLE |
-                                      RQFCR_RJE | RQFCR_AND);
-
-                       start = i;
-                       size = 0;
-               }
-               size++;
-               prev = mask_table[i].block;
-       }
-}
-
-/* Reduces the number of masks needed in the filer table to save entries
- * This is done by sorting the masks of a depended block. A depended block is
- * identified by gluing ANDs or CLE. The sorting order toggles after every
- * block. Of course entries in scope of a mask must change their location with
- * it.
- */
-static int gfar_optimize_filer_masks(struct filer_table *tab)
-{
-       struct filer_table *temp_table;
-       struct gfar_mask_entry *mask_table;
-
-       u32 and_index = 0, previous_mask = 0, i = 0, j = 0, size = 0;
-       s32 ret = 0;
-
-       /* We need a copy of the filer table because
-        * we want to change its order
-        */
-       temp_table = kmemdup(tab, sizeof(*temp_table), GFP_KERNEL);
-       if (temp_table == NULL)
-               return -ENOMEM;
-
-       mask_table = kcalloc(MAX_FILER_CACHE_IDX / 2 + 1,
-                            sizeof(struct gfar_mask_entry), GFP_KERNEL);
-
-       if (mask_table == NULL) {
-               ret = -ENOMEM;
-               goto end;
-       }
-
-       and_index = gfar_generate_mask_table(mask_table, tab);
-
-       gfar_sort_mask_table(mask_table, temp_table, and_index);
-
-       /* Now we can copy the data from our duplicated filer table to
-        * the real one in the order the mask table says
-        */
-       for (i = 0; i < and_index; i++) {
-               size = mask_table[i].end - mask_table[i].start + 1;
-               gfar_copy_filer_entries(&(tab->fe[j]),
-                               &(temp_table->fe[mask_table[i].start]), size);
-               j += size;
-       }
-
-       /* And finally we just have to check for duplicated masks and drop the
-        * second ones
-        */
-       for (i = 0; i < tab->index && i < MAX_FILER_CACHE_IDX; i++) {
-               if (tab->fe[i].ctrl == 0x80) {
-                       previous_mask = i++;
-                       break;
-               }
-       }
-       for (; i < tab->index && i < MAX_FILER_CACHE_IDX; i++) {
-               if (tab->fe[i].ctrl == 0x80) {
-                       if (tab->fe[i].prop == tab->fe[previous_mask].prop) {
-                               /* Two identical ones found!
-                                * So drop the second one!
-                                */
-                               gfar_trim_filer_entries(i, i, tab);
-                       } else
-                               /* Not identical! */
-                               previous_mask = i;
-               }
-       }
-
-       kfree(mask_table);
-end:   kfree(temp_table);
-       return ret;
-}
-
 /* Write the bit-pattern from software's buffer to hardware registers */
 static int gfar_write_filer_table(struct gfar_private *priv,
                                  struct filer_table *tab)
@@ -1586,11 +1258,10 @@ static int gfar_write_filer_table(struct gfar_private *priv,
                return -EBUSY;
 
        /* Fill regular entries */
-       for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].prop);
-            i++)
+       for (; i < MAX_FILER_IDX && (tab->fe[i].ctrl | tab->fe[i].prop); i++)
                gfar_write_filer(priv, i, tab->fe[i].ctrl, tab->fe[i].prop);
        /* Fill the rest with fall-troughs */
-       for (; i < MAX_FILER_IDX - 1; i++)
+       for (; i < MAX_FILER_IDX; i++)
                gfar_write_filer(priv, i, 0x60, 0xFFFFFFFF);
        /* Last entry must be default accept
         * because that's what people expect
@@ -1624,7 +1295,6 @@ static int gfar_process_filer_changes(struct gfar_private *priv)
 {
        struct ethtool_flow_spec_container *j;
        struct filer_table *tab;
-       s32 i = 0;
        s32 ret = 0;
 
        /* So index is set to zero, too! */
@@ -1649,17 +1319,6 @@ static int gfar_process_filer_changes(struct gfar_private *priv)
                }
        }
 
-       i = tab->index;
-
-       /* Optimizations to save entries */
-       gfar_cluster_filer(tab);
-       gfar_optimize_filer_masks(tab);
-
-       pr_debug("\tSummary:\n"
-                "\tData on hardware: %d\n"
-                "\tCompression rate: %d%%\n",
-                tab->index, 100 - (100 * tab->index) / i);
-
        /* Write everything to hardware */
        ret = gfar_write_filer_table(priv, tab);
        if (ret == -EBUSY) {
@@ -1725,13 +1384,14 @@ static int gfar_add_cls(struct gfar_private *priv,
        }
 
 process:
+       priv->rx_list.count++;
        ret = gfar_process_filer_changes(priv);
        if (ret)
                goto clean_list;
-       priv->rx_list.count++;
        return ret;
 
 clean_list:
+       priv->rx_list.count--;
        list_del(&temp->list);
 clean_mem:
        kfree(temp);
index 370e20ed224c5c76eaca92954be5800d09d81ada..62e48bc0cb23ba98ed2cb2c447af288bd1c3906d 100644 (file)
@@ -1462,7 +1462,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                     struct mvneta_rx_queue *rxq)
 {
        struct net_device *dev = pp->dev;
-       int rx_done, rx_filled;
+       int rx_done;
        u32 rcvd_pkts = 0;
        u32 rcvd_bytes = 0;
 
@@ -1473,7 +1473,6 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                rx_todo = rx_done;
 
        rx_done = 0;
-       rx_filled = 0;
 
        /* Fairness NAPI loop */
        while (rx_done < rx_todo) {
@@ -1484,7 +1483,6 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                int rx_bytes, err;
 
                rx_done++;
-               rx_filled++;
                rx_status = rx_desc->status;
                rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
                data = (unsigned char *)rx_desc->buf_cookie;
@@ -1524,6 +1522,14 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                        continue;
                }
 
+               /* Refill processing */
+               err = mvneta_rx_refill(pp, rx_desc);
+               if (err) {
+                       netdev_err(dev, "Linux processing - Can't refill\n");
+                       rxq->missed++;
+                       goto err_drop_frame;
+               }
+
                skb = build_skb(data, pp->frag_size > PAGE_SIZE ? 0 : pp->frag_size);
                if (!skb)
                        goto err_drop_frame;
@@ -1543,14 +1549,6 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                mvneta_rx_csum(pp, rx_status, skb);
 
                napi_gro_receive(&pp->napi, skb);
-
-               /* Refill processing */
-               err = mvneta_rx_refill(pp, rx_desc);
-               if (err) {
-                       netdev_err(dev, "Linux processing - Can't refill\n");
-                       rxq->missed++;
-                       rx_filled--;
-               }
        }
 
        if (rcvd_pkts) {
@@ -1563,7 +1561,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
        }
 
        /* Update rxq management counters */
-       mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_filled);
+       mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done);
 
        return rx_done;
 }
index 3e8b1bfb1f2e316212bd9b60fa06522ca4dc68db..d9884fd15b453e2486177d58b7fc40bcd5aaf7cc 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/of_address.h>
 #include <linux/phy.h>
 #include <linux/clk.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
 #include <uapi/linux/ppp_defs.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 
 /* Coalescing */
 #define MVPP2_TXDONE_COAL_PKTS_THRESH  15
+#define MVPP2_TXDONE_HRTIMER_PERIOD_NS 1000000UL
 #define MVPP2_RX_COAL_PKTS             32
 #define MVPP2_RX_COAL_USEC             100
 
@@ -660,6 +663,14 @@ struct mvpp2_pcpu_stats {
        u64     tx_bytes;
 };
 
+/* Per-CPU port control */
+struct mvpp2_port_pcpu {
+       struct hrtimer tx_done_timer;
+       bool timer_scheduled;
+       /* Tasklet for egress finalization */
+       struct tasklet_struct tx_done_tasklet;
+};
+
 struct mvpp2_port {
        u8 id;
 
@@ -679,6 +690,9 @@ struct mvpp2_port {
        u32 pending_cause_rx;
        struct napi_struct napi;
 
+       /* Per-CPU port control */
+       struct mvpp2_port_pcpu __percpu *pcpu;
+
        /* Flags */
        unsigned long flags;
 
@@ -776,6 +790,9 @@ struct mvpp2_txq_pcpu {
        /* Array of transmitted skb */
        struct sk_buff **tx_skb;
 
+       /* Array of transmitted buffers' physical addresses */
+       dma_addr_t *tx_buffs;
+
        /* Index of last TX DMA descriptor that was inserted */
        int txq_put_index;
 
@@ -913,8 +930,6 @@ struct mvpp2_bm_pool {
        /* Occupied buffers indicator */
        atomic_t in_use;
        int in_use_thresh;
-
-       spinlock_t lock;
 };
 
 struct mvpp2_buff_hdr {
@@ -963,9 +978,13 @@ static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu)
 }
 
 static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu,
-                             struct sk_buff *skb)
+                             struct sk_buff *skb,
+                             struct mvpp2_tx_desc *tx_desc)
 {
        txq_pcpu->tx_skb[txq_pcpu->txq_put_index] = skb;
+       if (skb)
+               txq_pcpu->tx_buffs[txq_pcpu->txq_put_index] =
+                                                        tx_desc->buf_phys_addr;
        txq_pcpu->txq_put_index++;
        if (txq_pcpu->txq_put_index == txq_pcpu->size)
                txq_pcpu->txq_put_index = 0;
@@ -3376,7 +3395,6 @@ static int mvpp2_bm_pool_create(struct platform_device *pdev,
        bm_pool->pkt_size = 0;
        bm_pool->buf_num = 0;
        atomic_set(&bm_pool->in_use, 0);
-       spin_lock_init(&bm_pool->lock);
 
        return 0;
 }
@@ -3647,7 +3665,6 @@ static struct mvpp2_bm_pool *
 mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
                  int pkt_size)
 {
-       unsigned long flags = 0;
        struct mvpp2_bm_pool *new_pool = &port->priv->bm_pools[pool];
        int num;
 
@@ -3656,8 +3673,6 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
                return NULL;
        }
 
-       spin_lock_irqsave(&new_pool->lock, flags);
-
        if (new_pool->type == MVPP2_BM_FREE)
                new_pool->type = type;
 
@@ -3686,8 +3701,6 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
                if (num != pkts_num) {
                        WARN(1, "pool %d: %d of %d allocated\n",
                             new_pool->id, num, pkts_num);
-                       /* We need to undo the bufs_add() allocations */
-                       spin_unlock_irqrestore(&new_pool->lock, flags);
                        return NULL;
                }
        }
@@ -3695,15 +3708,12 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
        mvpp2_bm_pool_bufsize_set(port->priv, new_pool,
                                  MVPP2_RX_BUF_SIZE(new_pool->pkt_size));
 
-       spin_unlock_irqrestore(&new_pool->lock, flags);
-
        return new_pool;
 }
 
 /* Initialize pools for swf */
 static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
 {
-       unsigned long flags = 0;
        int rxq;
 
        if (!port->pool_long) {
@@ -3714,9 +3724,7 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
                if (!port->pool_long)
                        return -ENOMEM;
 
-               spin_lock_irqsave(&port->pool_long->lock, flags);
                port->pool_long->port_map |= (1 << port->id);
-               spin_unlock_irqrestore(&port->pool_long->lock, flags);
 
                for (rxq = 0; rxq < rxq_number; rxq++)
                        mvpp2_rxq_long_pool_set(port, rxq, port->pool_long->id);
@@ -3730,9 +3738,7 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
                if (!port->pool_short)
                        return -ENOMEM;
 
-               spin_lock_irqsave(&port->pool_short->lock, flags);
                port->pool_short->port_map |= (1 << port->id);
-               spin_unlock_irqrestore(&port->pool_short->lock, flags);
 
                for (rxq = 0; rxq < rxq_number; rxq++)
                        mvpp2_rxq_short_pool_set(port, rxq,
@@ -3806,7 +3812,6 @@ static void mvpp2_interrupts_unmask(void *arg)
 
        mvpp2_write(port->priv, MVPP2_ISR_RX_TX_MASK_REG(port->id),
                    (MVPP2_CAUSE_MISC_SUM_MASK |
-                    MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK |
                     MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK));
 }
 
@@ -4382,23 +4387,6 @@ static void mvpp2_rx_time_coal_set(struct mvpp2_port *port,
        rxq->time_coal = usec;
 }
 
-/* Set threshold for TX_DONE pkts coalescing */
-static void mvpp2_tx_done_pkts_coal_set(void *arg)
-{
-       struct mvpp2_port *port = arg;
-       int queue;
-       u32 val;
-
-       for (queue = 0; queue < txq_number; queue++) {
-               struct mvpp2_tx_queue *txq = port->txqs[queue];
-
-               val = (txq->done_pkts_coal << MVPP2_TRANSMITTED_THRESH_OFFSET) &
-                      MVPP2_TRANSMITTED_THRESH_MASK;
-               mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id);
-               mvpp2_write(port->priv, MVPP2_TXQ_THRESH_REG, val);
-       }
-}
-
 /* Free Tx queue skbuffs */
 static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
                                struct mvpp2_tx_queue *txq,
@@ -4407,8 +4395,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
        int i;
 
        for (i = 0; i < num; i++) {
-               struct mvpp2_tx_desc *tx_desc = txq->descs +
-                                                       txq_pcpu->txq_get_index;
+               dma_addr_t buf_phys_addr =
+                                   txq_pcpu->tx_buffs[txq_pcpu->txq_get_index];
                struct sk_buff *skb = txq_pcpu->tx_skb[txq_pcpu->txq_get_index];
 
                mvpp2_txq_inc_get(txq_pcpu);
@@ -4416,8 +4404,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
                if (!skb)
                        continue;
 
-               dma_unmap_single(port->dev->dev.parent, tx_desc->buf_phys_addr,
-                                tx_desc->data_size, DMA_TO_DEVICE);
+               dma_unmap_single(port->dev->dev.parent, buf_phys_addr,
+                                skb_headlen(skb), DMA_TO_DEVICE);
                dev_kfree_skb_any(skb);
        }
 }
@@ -4433,7 +4421,7 @@ static inline struct mvpp2_rx_queue *mvpp2_get_rx_queue(struct mvpp2_port *port,
 static inline struct mvpp2_tx_queue *mvpp2_get_tx_queue(struct mvpp2_port *port,
                                                        u32 cause)
 {
-       int queue = fls(cause >> 16) - 1;
+       int queue = fls(cause) - 1;
 
        return port->txqs[queue];
 }
@@ -4460,6 +4448,29 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
                        netif_tx_wake_queue(nq);
 }
 
+static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause)
+{
+       struct mvpp2_tx_queue *txq;
+       struct mvpp2_txq_pcpu *txq_pcpu;
+       unsigned int tx_todo = 0;
+
+       while (cause) {
+               txq = mvpp2_get_tx_queue(port, cause);
+               if (!txq)
+                       break;
+
+               txq_pcpu = this_cpu_ptr(txq->pcpu);
+
+               if (txq_pcpu->count) {
+                       mvpp2_txq_done(port, txq, txq_pcpu);
+                       tx_todo += txq_pcpu->count;
+               }
+
+               cause &= ~(1 << txq->log_id);
+       }
+       return tx_todo;
+}
+
 /* Rx/Tx queue initialization/cleanup methods */
 
 /* Allocate and initialize descriptors for aggr TXQ */
@@ -4649,12 +4660,13 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
                txq_pcpu->tx_skb = kmalloc(txq_pcpu->size *
                                           sizeof(*txq_pcpu->tx_skb),
                                           GFP_KERNEL);
-               if (!txq_pcpu->tx_skb) {
-                       dma_free_coherent(port->dev->dev.parent,
-                                         txq->size * MVPP2_DESC_ALIGNED_SIZE,
-                                         txq->descs, txq->descs_phys);
-                       return -ENOMEM;
-               }
+               if (!txq_pcpu->tx_skb)
+                       goto error;
+
+               txq_pcpu->tx_buffs = kmalloc(txq_pcpu->size *
+                                            sizeof(dma_addr_t), GFP_KERNEL);
+               if (!txq_pcpu->tx_buffs)
+                       goto error;
 
                txq_pcpu->count = 0;
                txq_pcpu->reserved_num = 0;
@@ -4663,6 +4675,19 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
        }
 
        return 0;
+
+error:
+       for_each_present_cpu(cpu) {
+               txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
+               kfree(txq_pcpu->tx_skb);
+               kfree(txq_pcpu->tx_buffs);
+       }
+
+       dma_free_coherent(port->dev->dev.parent,
+                         txq->size * MVPP2_DESC_ALIGNED_SIZE,
+                         txq->descs, txq->descs_phys);
+
+       return -ENOMEM;
 }
 
 /* Free allocated TXQ resources */
@@ -4675,6 +4700,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port,
        for_each_present_cpu(cpu) {
                txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
                kfree(txq_pcpu->tx_skb);
+               kfree(txq_pcpu->tx_buffs);
        }
 
        if (txq->descs)
@@ -4805,7 +4831,6 @@ static int mvpp2_setup_txqs(struct mvpp2_port *port)
                        goto err_cleanup;
        }
 
-       on_each_cpu(mvpp2_tx_done_pkts_coal_set, port, 1);
        on_each_cpu(mvpp2_txq_sent_counter_clear, port, 1);
        return 0;
 
@@ -4887,6 +4912,49 @@ static void mvpp2_link_event(struct net_device *dev)
        }
 }
 
+static void mvpp2_timer_set(struct mvpp2_port_pcpu *port_pcpu)
+{
+       ktime_t interval;
+
+       if (!port_pcpu->timer_scheduled) {
+               port_pcpu->timer_scheduled = true;
+               interval = ktime_set(0, MVPP2_TXDONE_HRTIMER_PERIOD_NS);
+               hrtimer_start(&port_pcpu->tx_done_timer, interval,
+                             HRTIMER_MODE_REL_PINNED);
+       }
+}
+
+static void mvpp2_tx_proc_cb(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct mvpp2_port *port = netdev_priv(dev);
+       struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu);
+       unsigned int tx_todo, cause;
+
+       if (!netif_running(dev))
+               return;
+       port_pcpu->timer_scheduled = false;
+
+       /* Process all the Tx queues */
+       cause = (1 << txq_number) - 1;
+       tx_todo = mvpp2_tx_done(port, cause);
+
+       /* Set the timer in case not all the packets were processed */
+       if (tx_todo)
+               mvpp2_timer_set(port_pcpu);
+}
+
+static enum hrtimer_restart mvpp2_hr_timer_cb(struct hrtimer *timer)
+{
+       struct mvpp2_port_pcpu *port_pcpu = container_of(timer,
+                                                        struct mvpp2_port_pcpu,
+                                                        tx_done_timer);
+
+       tasklet_schedule(&port_pcpu->tx_done_tasklet);
+
+       return HRTIMER_NORESTART;
+}
+
 /* Main RX/TX processing routines */
 
 /* Display more error info */
@@ -5144,11 +5212,11 @@ static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb,
                if (i == (skb_shinfo(skb)->nr_frags - 1)) {
                        /* Last descriptor */
                        tx_desc->command = MVPP2_TXD_L_DESC;
-                       mvpp2_txq_inc_put(txq_pcpu, skb);
+                       mvpp2_txq_inc_put(txq_pcpu, skb, tx_desc);
                } else {
                        /* Descriptor in the middle: Not First, Not Last */
                        tx_desc->command = 0;
-                       mvpp2_txq_inc_put(txq_pcpu, NULL);
+                       mvpp2_txq_inc_put(txq_pcpu, NULL, tx_desc);
                }
        }
 
@@ -5214,12 +5282,12 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
                /* First and Last descriptor */
                tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC;
                tx_desc->command = tx_cmd;
-               mvpp2_txq_inc_put(txq_pcpu, skb);
+               mvpp2_txq_inc_put(txq_pcpu, skb, tx_desc);
        } else {
                /* First but not Last */
                tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_PADDING_DISABLE;
                tx_desc->command = tx_cmd;
-               mvpp2_txq_inc_put(txq_pcpu, NULL);
+               mvpp2_txq_inc_put(txq_pcpu, NULL, tx_desc);
 
                /* Continue with other skb fragments */
                if (mvpp2_tx_frag_process(port, skb, aggr_txq, txq)) {
@@ -5255,6 +5323,17 @@ out:
                dev_kfree_skb_any(skb);
        }
 
+       /* Finalize TX processing */
+       if (txq_pcpu->count >= txq->done_pkts_coal)
+               mvpp2_txq_done(port, txq, txq_pcpu);
+
+       /* Set the timer in case not all frags were processed */
+       if (txq_pcpu->count <= frags && txq_pcpu->count > 0) {
+               struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu);
+
+               mvpp2_timer_set(port_pcpu);
+       }
+
        return NETDEV_TX_OK;
 }
 
@@ -5268,10 +5347,11 @@ static inline void mvpp2_cause_error(struct net_device *dev, int cause)
                netdev_err(dev, "tx fifo underrun error\n");
 }
 
-static void mvpp2_txq_done_percpu(void *arg)
+static int mvpp2_poll(struct napi_struct *napi, int budget)
 {
-       struct mvpp2_port *port = arg;
-       u32 cause_rx_tx, cause_tx, cause_misc;
+       u32 cause_rx_tx, cause_rx, cause_misc;
+       int rx_done = 0;
+       struct mvpp2_port *port = netdev_priv(napi->dev);
 
        /* Rx/Tx cause register
         *
@@ -5285,7 +5365,7 @@ static void mvpp2_txq_done_percpu(void *arg)
         */
        cause_rx_tx = mvpp2_read(port->priv,
                                 MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
-       cause_tx = cause_rx_tx & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
+       cause_rx_tx &= ~MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
        cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK;
 
        if (cause_misc) {
@@ -5297,26 +5377,6 @@ static void mvpp2_txq_done_percpu(void *arg)
                            cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK);
        }
 
-       /* Release TX descriptors */
-       if (cause_tx) {
-               struct mvpp2_tx_queue *txq = mvpp2_get_tx_queue(port, cause_tx);
-               struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu);
-
-               if (txq_pcpu->count)
-                       mvpp2_txq_done(port, txq, txq_pcpu);
-       }
-}
-
-static int mvpp2_poll(struct napi_struct *napi, int budget)
-{
-       u32 cause_rx_tx, cause_rx;
-       int rx_done = 0;
-       struct mvpp2_port *port = netdev_priv(napi->dev);
-
-       on_each_cpu(mvpp2_txq_done_percpu, port, 1);
-
-       cause_rx_tx = mvpp2_read(port->priv,
-                                MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
        cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
 
        /* Process RX packets */
@@ -5561,6 +5621,8 @@ err_cleanup_rxqs:
 static int mvpp2_stop(struct net_device *dev)
 {
        struct mvpp2_port *port = netdev_priv(dev);
+       struct mvpp2_port_pcpu *port_pcpu;
+       int cpu;
 
        mvpp2_stop_dev(port);
        mvpp2_phy_disconnect(port);
@@ -5569,6 +5631,13 @@ static int mvpp2_stop(struct net_device *dev)
        on_each_cpu(mvpp2_interrupts_mask, port, 1);
 
        free_irq(port->irq, port);
+       for_each_present_cpu(cpu) {
+               port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+
+               hrtimer_cancel(&port_pcpu->tx_done_timer);
+               port_pcpu->timer_scheduled = false;
+               tasklet_kill(&port_pcpu->tx_done_tasklet);
+       }
        mvpp2_cleanup_rxqs(port);
        mvpp2_cleanup_txqs(port);
 
@@ -5784,7 +5853,6 @@ static int mvpp2_ethtool_set_coalesce(struct net_device *dev,
                txq->done_pkts_coal = c->tx_max_coalesced_frames;
        }
 
-       on_each_cpu(mvpp2_tx_done_pkts_coal_set, port, 1);
        return 0;
 }
 
@@ -6035,6 +6103,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
 {
        struct device_node *phy_node;
        struct mvpp2_port *port;
+       struct mvpp2_port_pcpu *port_pcpu;
        struct net_device *dev;
        struct resource *res;
        const char *dt_mac_addr;
@@ -6044,7 +6113,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
        int features;
        int phy_mode;
        int priv_common_regs_num = 2;
-       int err, i;
+       int err, i, cpu;
 
        dev = alloc_etherdev_mqs(sizeof(struct mvpp2_port), txq_number,
                                 rxq_number);
@@ -6135,6 +6204,24 @@ static int mvpp2_port_probe(struct platform_device *pdev,
        }
        mvpp2_port_power_up(port);
 
+       port->pcpu = alloc_percpu(struct mvpp2_port_pcpu);
+       if (!port->pcpu) {
+               err = -ENOMEM;
+               goto err_free_txq_pcpu;
+       }
+
+       for_each_present_cpu(cpu) {
+               port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+
+               hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC,
+                            HRTIMER_MODE_REL_PINNED);
+               port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb;
+               port_pcpu->timer_scheduled = false;
+
+               tasklet_init(&port_pcpu->tx_done_tasklet, mvpp2_tx_proc_cb,
+                            (unsigned long)dev);
+       }
+
        netif_napi_add(dev, &port->napi, mvpp2_poll, NAPI_POLL_WEIGHT);
        features = NETIF_F_SG | NETIF_F_IP_CSUM;
        dev->features = features | NETIF_F_RXCSUM;
@@ -6144,7 +6231,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
        err = register_netdev(dev);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to register netdev\n");
-               goto err_free_txq_pcpu;
+               goto err_free_port_pcpu;
        }
        netdev_info(dev, "Using %s mac address %pM\n", mac_from, dev->dev_addr);
 
@@ -6153,6 +6240,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
        priv->port_list[id] = port;
        return 0;
 
+err_free_port_pcpu:
+       free_percpu(port->pcpu);
 err_free_txq_pcpu:
        for (i = 0; i < txq_number; i++)
                free_percpu(port->txqs[i]->pcpu);
@@ -6171,6 +6260,7 @@ static void mvpp2_port_remove(struct mvpp2_port *port)
        int i;
 
        unregister_netdev(port->dev);
+       free_percpu(port->pcpu);
        free_percpu(port->stats);
        for (i = 0; i < txq_number; i++)
                free_percpu(port->txqs[i]->pcpu);
index 82040137d7d9723a0ab027fe72bc25a3063368b3..0a3202047569c707a28f62376466e72fdcd8cd00 100644 (file)
@@ -686,6 +686,7 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
 {
        struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
        struct mlx4_cmd_context *context;
+       long ret_wait;
        int err = 0;
 
        down(&cmd->event_sem);
@@ -711,8 +712,20 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
        if (err)
                goto out_reset;
 
-       if (!wait_for_completion_timeout(&context->done,
-                                        msecs_to_jiffies(timeout))) {
+       if (op == MLX4_CMD_SENSE_PORT) {
+               ret_wait =
+                       wait_for_completion_interruptible_timeout(&context->done,
+                                                                 msecs_to_jiffies(timeout));
+               if (ret_wait < 0) {
+                       context->fw_status = 0;
+                       context->out_param = 0;
+                       context->result = 0;
+               }
+       } else {
+               ret_wait = (long)wait_for_completion_timeout(&context->done,
+                                                            msecs_to_jiffies(timeout));
+       }
+       if (!ret_wait) {
                mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n",
                          op);
                if (op == MLX4_CMD_NOP) {
index 7a4f20bb7fcb4c2640ad8111f5a98ff95088075c..9c145dddd7175fffda22c71a8f31d4d27d807ceb 100644 (file)
@@ -246,7 +246,6 @@ static int mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv,
 
 static inline bool mlx4_en_is_ring_empty(struct mlx4_en_rx_ring *ring)
 {
-       BUG_ON((u32)(ring->prod - ring->cons) > ring->actual_size);
        return ring->prod == ring->cons;
 }
 
index aae13adfb492b885bcf2fba03b042b949c3f5575..8e81e53c370e7d54e6367c012212cccc73ee26fd 100644 (file)
@@ -601,7 +601,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
                                                        continue;
                                                mlx4_dbg(dev, "%s: Sending MLX4_PORT_CHANGE_SUBTYPE_DOWN to slave: %d, port:%d\n",
                                                         __func__, i, port);
-                                               s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state;
+                                               s_info = &priv->mfunc.master.vf_oper[i].vport[port].state;
                                                if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) {
                                                        eqe->event.port_change.port =
                                                                cpu_to_be32(
@@ -640,7 +640,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
                                                        continue;
                                                if (i == mlx4_master_func_num(dev))
                                                        continue;
-                                               s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state;
+                                               s_info = &priv->mfunc.master.vf_oper[i].vport[port].state;
                                                if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) {
                                                        eqe->event.port_change.port =
                                                                cpu_to_be32(
index 12fbfcb44d8acdedf08fef880a12e53145f8836e..29c2a017a450277657a5d5e9ad4a4878575cbb2c 100644 (file)
@@ -2273,6 +2273,11 @@ static int mlx4_allocate_default_counters(struct mlx4_dev *dev)
                } else if (err == -ENOENT) {
                        err = 0;
                        continue;
+               } else if (mlx4_is_slave(dev) && err == -EINVAL) {
+                       priv->def_counter[port] = MLX4_SINK_COUNTER_INDEX(dev);
+                       mlx4_warn(dev, "can't allocate counter from old PF driver, using index %d\n",
+                                 MLX4_SINK_COUNTER_INDEX(dev));
+                       err = 0;
                } else {
                        mlx4_err(dev, "%s: failed to allocate default counter port %d err %d\n",
                                 __func__, port + 1, err);
index afad529838de748efc9f9253c6fde42abbe954a3..06e3e1e54c35d6078321d792d1e0e537ec95a207 100644 (file)
@@ -391,6 +391,8 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
        /* disable cmdif checksum */
        MLX5_SET(cmd_hca_cap, set_hca_cap, cmdif_checksum, 0);
 
+       MLX5_SET(cmd_hca_cap, set_hca_cap, log_uar_page_sz, PAGE_SHIFT - 12);
+
        err = set_caps(dev, set_ctx, set_sz);
 
 query_ex:
index 33669c29b341cb42bb106ec2c634663d0adb2415..753ea8bad953c3a75487e3a544cc4106d4a46f68 100644 (file)
@@ -1415,7 +1415,7 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
        if (fw->size & 0xF) {
                addr = dest + size;
                for (i = 0; i < (fw->size & 0xF); i++)
-                       data[i] = temp[size + i];
+                       data[i] = ((u8 *)temp)[size + i];
                for (; i < 16; i++)
                        data[i] = 0;
                ret = qlcnic_ms_mem_write128(adapter, addr,
index 3df51faf18ae3ba8ce6bb7f49e6f51e4da1be738..f790f61ea78a2b4f1008da82eca29132ff5bdcc0 100644 (file)
@@ -4875,10 +4875,12 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_46:
        case RTL_GIGA_MAC_VER_47:
        case RTL_GIGA_MAC_VER_48:
+               RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
+               break;
        case RTL_GIGA_MAC_VER_49:
        case RTL_GIGA_MAC_VER_50:
        case RTL_GIGA_MAC_VER_51:
-               RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
+               RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
                break;
        default:
                RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
index fd9745714d903fa5945956709491be934ea02c67..78849dd4ef8e9463c2420c84cc583a927492df58 100644 (file)
@@ -228,9 +228,7 @@ static void ravb_ring_format(struct net_device *ndev, int q)
        struct ravb_desc *desc = NULL;
        int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q];
        int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q];
-       struct sk_buff *skb;
        dma_addr_t dma_addr;
-       void *buffer;
        int i;
 
        priv->cur_rx[q] = 0;
@@ -241,41 +239,28 @@ static void ravb_ring_format(struct net_device *ndev, int q)
        memset(priv->rx_ring[q], 0, rx_ring_size);
        /* Build RX ring buffer */
        for (i = 0; i < priv->num_rx_ring[q]; i++) {
-               priv->rx_skb[q][i] = NULL;
-               skb = netdev_alloc_skb(ndev, PKT_BUF_SZ + RAVB_ALIGN - 1);
-               if (!skb)
-                       break;
-               ravb_set_buffer_align(skb);
                /* RX descriptor */
                rx_desc = &priv->rx_ring[q][i];
                /* The size of the buffer should be on 16-byte boundary. */
                rx_desc->ds_cc = cpu_to_le16(ALIGN(PKT_BUF_SZ, 16));
-               dma_addr = dma_map_single(&ndev->dev, skb->data,
+               dma_addr = dma_map_single(&ndev->dev, priv->rx_skb[q][i]->data,
                                          ALIGN(PKT_BUF_SZ, 16),
                                          DMA_FROM_DEVICE);
-               if (dma_mapping_error(&ndev->dev, dma_addr)) {
-                       dev_kfree_skb(skb);
-                       break;
-               }
-               priv->rx_skb[q][i] = skb;
+               /* We just set the data size to 0 for a failed mapping which
+                * should prevent DMA from happening...
+                */
+               if (dma_mapping_error(&ndev->dev, dma_addr))
+                       rx_desc->ds_cc = cpu_to_le16(0);
                rx_desc->dptr = cpu_to_le32(dma_addr);
                rx_desc->die_dt = DT_FEMPTY;
        }
        rx_desc = &priv->rx_ring[q][i];
        rx_desc->dptr = cpu_to_le32((u32)priv->rx_desc_dma[q]);
        rx_desc->die_dt = DT_LINKFIX; /* type */
-       priv->dirty_rx[q] = (u32)(i - priv->num_rx_ring[q]);
 
        memset(priv->tx_ring[q], 0, tx_ring_size);
        /* Build TX ring buffer */
        for (i = 0; i < priv->num_tx_ring[q]; i++) {
-               priv->tx_skb[q][i] = NULL;
-               priv->tx_buffers[q][i] = NULL;
-               buffer = kmalloc(PKT_BUF_SZ + RAVB_ALIGN - 1, GFP_KERNEL);
-               if (!buffer)
-                       break;
-               /* Aligned TX buffer */
-               priv->tx_buffers[q][i] = buffer;
                tx_desc = &priv->tx_ring[q][i];
                tx_desc->die_dt = DT_EEMPTY;
        }
@@ -298,7 +283,10 @@ static void ravb_ring_format(struct net_device *ndev, int q)
 static int ravb_ring_init(struct net_device *ndev, int q)
 {
        struct ravb_private *priv = netdev_priv(ndev);
+       struct sk_buff *skb;
        int ring_size;
+       void *buffer;
+       int i;
 
        /* Allocate RX and TX skb rings */
        priv->rx_skb[q] = kcalloc(priv->num_rx_ring[q],
@@ -308,12 +296,28 @@ static int ravb_ring_init(struct net_device *ndev, int q)
        if (!priv->rx_skb[q] || !priv->tx_skb[q])
                goto error;
 
+       for (i = 0; i < priv->num_rx_ring[q]; i++) {
+               skb = netdev_alloc_skb(ndev, PKT_BUF_SZ + RAVB_ALIGN - 1);
+               if (!skb)
+                       goto error;
+               ravb_set_buffer_align(skb);
+               priv->rx_skb[q][i] = skb;
+       }
+
        /* Allocate rings for the aligned buffers */
        priv->tx_buffers[q] = kcalloc(priv->num_tx_ring[q],
                                      sizeof(*priv->tx_buffers[q]), GFP_KERNEL);
        if (!priv->tx_buffers[q])
                goto error;
 
+       for (i = 0; i < priv->num_tx_ring[q]; i++) {
+               buffer = kmalloc(PKT_BUF_SZ + RAVB_ALIGN - 1, GFP_KERNEL);
+               if (!buffer)
+                       goto error;
+               /* Aligned TX buffer */
+               priv->tx_buffers[q][i] = buffer;
+       }
+
        /* Allocate all RX descriptors. */
        ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1);
        priv->rx_ring[q] = dma_alloc_coherent(NULL, ring_size,
@@ -524,6 +528,10 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q)
                if (--boguscnt < 0)
                        break;
 
+               /* We use 0-byte descriptors to mark the DMA mapping errors */
+               if (!pkt_len)
+                       continue;
+
                if (desc_status & MSC_MC)
                        stats->multicast++;
 
@@ -543,10 +551,9 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q)
 
                        skb = priv->rx_skb[q][entry];
                        priv->rx_skb[q][entry] = NULL;
-                       dma_sync_single_for_cpu(&ndev->dev,
-                                               le32_to_cpu(desc->dptr),
-                                               ALIGN(PKT_BUF_SZ, 16),
-                                               DMA_FROM_DEVICE);
+                       dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr),
+                                        ALIGN(PKT_BUF_SZ, 16),
+                                        DMA_FROM_DEVICE);
                        get_ts &= (q == RAVB_NC) ?
                                        RAVB_RXTSTAMP_TYPE_V2_L2_EVENT :
                                        ~RAVB_RXTSTAMP_TYPE_V2_L2_EVENT;
@@ -584,17 +591,15 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q)
                        if (!skb)
                                break;  /* Better luck next round. */
                        ravb_set_buffer_align(skb);
-                       dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr),
-                                        ALIGN(PKT_BUF_SZ, 16),
-                                        DMA_FROM_DEVICE);
                        dma_addr = dma_map_single(&ndev->dev, skb->data,
                                                  le16_to_cpu(desc->ds_cc),
                                                  DMA_FROM_DEVICE);
                        skb_checksum_none_assert(skb);
-                       if (dma_mapping_error(&ndev->dev, dma_addr)) {
-                               dev_kfree_skb_any(skb);
-                               break;
-                       }
+                       /* We just set the data size to 0 for a failed mapping
+                        * which should prevent DMA  from happening...
+                        */
+                       if (dma_mapping_error(&ndev->dev, dma_addr))
+                               desc->ds_cc = cpu_to_le16(0);
                        desc->dptr = cpu_to_le32(dma_addr);
                        priv->rx_skb[q][entry] = skb;
                }
@@ -1279,7 +1284,6 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        u32 dma_addr;
        void *buffer;
        u32 entry;
-       u32 tccr;
 
        spin_lock_irqsave(&priv->lock, flags);
        if (priv->cur_tx[q] - priv->dirty_tx[q] >= priv->num_tx_ring[q]) {
@@ -1328,9 +1332,7 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        dma_wmb();
        desc->die_dt = DT_FSINGLE;
 
-       tccr = ravb_read(ndev, TCCR);
-       if (!(tccr & (TCCR_TSRQ0 << q)))
-               ravb_write(ndev, tccr | (TCCR_TSRQ0 << q), TCCR);
+       ravb_write(ndev, ravb_read(ndev, TCCR) | (TCCR_TSRQ0 << q), TCCR);
 
        priv->cur_tx[q]++;
        if (priv->cur_tx[q] - priv->dirty_tx[q] >= priv->num_tx_ring[q] &&
index 2d8578cade03790782af7e97a1f59f9848301ae6..2e7f9a2834be320eef4a7bed44d8c787f72f3e65 100644 (file)
@@ -4821,6 +4821,7 @@ static void rocker_remove_ports(const struct rocker *rocker)
                rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE,
                                   ROCKER_OP_FLAG_REMOVE);
                unregister_netdev(rocker_port->dev);
+               free_netdev(rocker_port->dev);
        }
        kfree(rocker->ports);
 }
index 7e3129e7f143a9990c89780a8e6638f8182e4892..f0e4bb4e3ec59f9695957dee9dec55a02d450da8 100644 (file)
@@ -42,7 +42,7 @@
 #define NSS_COMMON_CLK_DIV_MASK                        0x7f
 
 #define NSS_COMMON_CLK_SRC_CTRL                        0x14
-#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x)      (1 << x)
+#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x)      (x)
 /* Mode is coded on 1 bit but is different depending on the MAC ID:
  * MAC0: QSGMII=0 RGMII=1
  * MAC1: QSGMII=0 SGMII=0 RGMII=1
@@ -291,7 +291,7 @@ static void *ipq806x_gmac_setup(struct platform_device *pdev)
 
        /* Configure the clock src according to the mode */
        regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val);
-       val &= ~NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
+       val &= ~(1 << NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id));
        switch (gmac->phy_mode) {
        case PHY_INTERFACE_MODE_RGMII:
                val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) <<
index 50f7a7a26821c7a40cb73294a4844406ea9caee5..864b476f7fd5a33b81ac2f6ea9b08e0cf99d299d 100644 (file)
@@ -2843,7 +2843,7 @@ int stmmac_dvr_probe(struct device *device,
        if (res->mac)
                memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);
 
-       dev_set_drvdata(device, priv);
+       dev_set_drvdata(device, priv->dev);
 
        /* Verify driver arguments */
        stmmac_verify_args();
index f3918c7e7eeb373a6736bb5145c33320acbabc53..bcdc8955c71945cf62e2d62e138d17a16f937949 100644 (file)
@@ -413,3 +413,7 @@ static int stmmac_pltfr_resume(struct device *dev)
 SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend,
                                       stmmac_pltfr_resume);
 EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
+
+MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
+MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
+MODULE_LICENSE("GPL");
index 0c5842aeb807014c632a2d713b366133d7021f56..ab6051a43134f4dd7296679ffe089203162e3aa7 100644 (file)
@@ -6658,10 +6658,8 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb,
                struct sk_buff *skb_new;
 
                skb_new = skb_realloc_headroom(skb, len);
-               if (!skb_new) {
-                       rp->tx_errors++;
+               if (!skb_new)
                        goto out_drop;
-               }
                kfree_skb(skb);
                skb = skb_new;
        } else
index f335bf119ab57d3e209a81e28cc7cbce5f9208c7..d155bf2573cd0ef00abc133074831cccc7f937b1 100644 (file)
@@ -793,9 +793,7 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id)
 static int cpsw_poll(struct napi_struct *napi, int budget)
 {
        struct cpsw_priv        *priv = napi_to_priv(napi);
-       int                     num_tx, num_rx;
-
-       num_tx = cpdma_chan_process(priv->txch, 128);
+       int                     num_rx;
 
        num_rx = cpdma_chan_process(priv->rxch, budget);
        if (num_rx < budget) {
@@ -810,9 +808,8 @@ static int cpsw_poll(struct napi_struct *napi, int budget)
                }
        }
 
-       if (num_rx || num_tx)
-               cpsw_dbg(priv, intr, "poll %d rx, %d tx pkts\n",
-                        num_rx, num_tx);
+       if (num_rx)
+               cpsw_dbg(priv, intr, "poll %d rx pkts\n", num_rx);
 
        return num_rx;
 }
index bbacf5cccec2fcbc3831e8f61b559d51a5211816..bb1bb72121c0474b8c1898540a28d21264479d6a 100644 (file)
@@ -85,7 +85,6 @@ struct netcp_intf {
        struct list_head        rxhook_list_head;
        unsigned int            rx_queue_id;
        void                    *rx_fdq[KNAV_DMA_FDQ_PER_CHAN];
-       u32                     rx_buffer_sizes[KNAV_DMA_FDQ_PER_CHAN];
        struct napi_struct      rx_napi;
        struct napi_struct      tx_napi;
 
@@ -223,6 +222,7 @@ void *netcp_device_find_module(struct netcp_device *netcp_device,
 
 /* SGMII functions */
 int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port);
+bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set);
 int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port);
 int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface);
 
index 5ec4ed3f6c8def7a6a6cf527cd9ac7ca73c09844..4755838c6137b462d6de262b38beadacdf099e98 100644 (file)
@@ -34,6 +34,7 @@
 #define NETCP_SOP_OFFSET       (NET_IP_ALIGN + NET_SKB_PAD)
 #define NETCP_NAPI_WEIGHT      64
 #define NETCP_TX_TIMEOUT       (5 * HZ)
+#define NETCP_PACKET_SIZE      (ETH_FRAME_LEN + ETH_FCS_LEN)
 #define NETCP_MIN_PACKET_SIZE  ETH_ZLEN
 #define NETCP_MAX_MCAST_ADDR   16
 
@@ -804,30 +805,28 @@ static void netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
        if (likely(fdq == 0)) {
                unsigned int primary_buf_len;
                /* Allocate a primary receive queue entry */
-               buf_len = netcp->rx_buffer_sizes[0] + NETCP_SOP_OFFSET;
+               buf_len = NETCP_PACKET_SIZE + NETCP_SOP_OFFSET;
                primary_buf_len = SKB_DATA_ALIGN(buf_len) +
                                SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 
-               if (primary_buf_len <= PAGE_SIZE) {
-                       bufptr = netdev_alloc_frag(primary_buf_len);
-                       pad[1] = primary_buf_len;
-               } else {
-                       bufptr = kmalloc(primary_buf_len, GFP_ATOMIC |
-                                        GFP_DMA32 | __GFP_COLD);
-                       pad[1] = 0;
-               }
+               bufptr = netdev_alloc_frag(primary_buf_len);
+               pad[1] = primary_buf_len;
 
                if (unlikely(!bufptr)) {
-                       dev_warn_ratelimited(netcp->ndev_dev, "Primary RX buffer alloc failed\n");
+                       dev_warn_ratelimited(netcp->ndev_dev,
+                                            "Primary RX buffer alloc failed\n");
                        goto fail;
                }
                dma = dma_map_single(netcp->dev, bufptr, buf_len,
                                     DMA_TO_DEVICE);
+               if (unlikely(dma_mapping_error(netcp->dev, dma)))
+                       goto fail;
+
                pad[0] = (u32)bufptr;
 
        } else {
                /* Allocate a secondary receive queue entry */
-               page = alloc_page(GFP_ATOMIC | GFP_DMA32 | __GFP_COLD);
+               page = alloc_page(GFP_ATOMIC | GFP_DMA | __GFP_COLD);
                if (unlikely(!page)) {
                        dev_warn_ratelimited(netcp->ndev_dev, "Secondary page alloc failed\n");
                        goto fail;
@@ -1010,7 +1009,7 @@ netcp_tx_map_skb(struct sk_buff *skb, struct netcp_intf *netcp)
 
        /* Map the linear buffer */
        dma_addr = dma_map_single(dev, skb->data, pkt_len, DMA_TO_DEVICE);
-       if (unlikely(!dma_addr)) {
+       if (unlikely(dma_mapping_error(dev, dma_addr))) {
                dev_err(netcp->ndev_dev, "Failed to map skb buffer\n");
                return NULL;
        }
@@ -1546,8 +1545,8 @@ static int netcp_setup_navigator_resources(struct net_device *ndev)
        knav_queue_disable_notify(netcp->rx_queue);
 
        /* open Rx FDQs */
-       for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN &&
-            netcp->rx_queue_depths[i] && netcp->rx_buffer_sizes[i]; ++i) {
+       for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && netcp->rx_queue_depths[i];
+            ++i) {
                snprintf(name, sizeof(name), "rx-fdq-%s-%d", ndev->name, i);
                netcp->rx_fdq[i] = knav_queue_open(name, KNAV_QUEUE_GP, 0);
                if (IS_ERR_OR_NULL(netcp->rx_fdq[i])) {
@@ -1617,11 +1616,11 @@ static int netcp_ndo_open(struct net_device *ndev)
        }
        mutex_unlock(&netcp_modules_lock);
 
-       netcp_rxpool_refill(netcp);
        napi_enable(&netcp->rx_napi);
        napi_enable(&netcp->tx_napi);
        knav_queue_enable_notify(netcp->tx_compl_q);
        knav_queue_enable_notify(netcp->rx_queue);
+       netcp_rxpool_refill(netcp);
        netif_tx_wake_all_queues(ndev);
        dev_dbg(netcp->ndev_dev, "netcp device %s opened\n", ndev->name);
        return 0;
@@ -1941,14 +1940,6 @@ static int netcp_create_interface(struct netcp_device *netcp_device,
                netcp->rx_queue_depths[0] = 128;
        }
 
-       ret = of_property_read_u32_array(node_interface, "rx-buffer-size",
-                                        netcp->rx_buffer_sizes,
-                                        KNAV_DMA_FDQ_PER_CHAN);
-       if (ret) {
-               dev_err(dev, "missing \"rx-buffer-size\" parameter\n");
-               netcp->rx_buffer_sizes[0] = 1536;
-       }
-
        ret = of_property_read_u32_array(node_interface, "rx-pool", temp, 2);
        if (ret < 0) {
                dev_err(dev, "missing \"rx-pool\" parameter\n");
@@ -2112,6 +2103,7 @@ probe_quit:
 static int netcp_remove(struct platform_device *pdev)
 {
        struct netcp_device *netcp_device = platform_get_drvdata(pdev);
+       struct netcp_intf *netcp_intf, *netcp_tmp;
        struct netcp_inst_modpriv *inst_modpriv, *tmp;
        struct netcp_module *module;
 
@@ -2123,10 +2115,17 @@ static int netcp_remove(struct platform_device *pdev)
                list_del(&inst_modpriv->inst_list);
                kfree(inst_modpriv);
        }
-       WARN(!list_empty(&netcp_device->interface_head), "%s interface list not empty!\n",
-            pdev->name);
 
-       devm_kfree(&pdev->dev, netcp_device);
+       /* now that all modules are removed, clean up the interfaces */
+       list_for_each_entry_safe(netcp_intf, netcp_tmp,
+                                &netcp_device->interface_head,
+                                interface_list) {
+               netcp_delete_interface(netcp_device, netcp_intf->ndev);
+       }
+
+       WARN(!list_empty(&netcp_device->interface_head),
+            "%s interface list not empty!\n", pdev->name);
+
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        platform_set_drvdata(pdev, NULL);
index 9b7e0a34c98b10aca5eed610c47f33b2eedbbd00..1974a8ae764aba6cb81e039239df68e91a58585b 100644 (file)
@@ -1901,11 +1901,28 @@ static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
        writel(slave->mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control));
 }
 
+static void gbe_sgmii_rtreset(struct gbe_priv *priv,
+                             struct gbe_slave *slave, bool set)
+{
+       void __iomem *sgmii_port_regs;
+
+       if (SLAVE_LINK_IS_XGMII(slave))
+               return;
+
+       if ((priv->ss_version == GBE_SS_VERSION_14) && (slave->slave_num >= 2))
+               sgmii_port_regs = priv->sgmii_port34_regs;
+       else
+               sgmii_port_regs = priv->sgmii_port_regs;
+
+       netcp_sgmii_rtreset(sgmii_port_regs, slave->slave_num, set);
+}
+
 static void gbe_slave_stop(struct gbe_intf *intf)
 {
        struct gbe_priv *gbe_dev = intf->gbe_dev;
        struct gbe_slave *slave = intf->slave;
 
+       gbe_sgmii_rtreset(gbe_dev, slave, true);
        gbe_port_reset(slave);
        /* Disable forwarding */
        cpsw_ale_control_set(gbe_dev->ale, slave->port_num,
@@ -1947,6 +1964,7 @@ static int gbe_slave_open(struct gbe_intf *gbe_intf)
 
        gbe_sgmii_config(priv, slave);
        gbe_port_reset(slave);
+       gbe_sgmii_rtreset(priv, slave, false);
        gbe_port_config(priv, slave, priv->rx_packet_max);
        gbe_set_slave_mac(slave, gbe_intf);
        /* enable forwarding */
@@ -2490,10 +2508,9 @@ static void free_secondary_ports(struct gbe_priv *gbe_dev)
 {
        struct gbe_slave *slave;
 
-       for (;;) {
+       while (!list_empty(&gbe_dev->secondary_slaves)) {
                slave = first_sec_slave(gbe_dev);
-               if (!slave)
-                       break;
+
                if (slave->phy)
                        phy_disconnect(slave->phy);
                list_del(&slave->slave_list);
@@ -2839,14 +2856,13 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
                                      &gbe_dev->dma_chan_name);
        if (ret < 0) {
                dev_err(dev, "missing \"tx-channel\" parameter\n");
-               ret = -ENODEV;
-               goto quit;
+               return -EINVAL;
        }
 
        if (!strcmp(node->name, "gbe")) {
                ret = get_gbe_resource_version(gbe_dev, node);
                if (ret)
-                       goto quit;
+                       return ret;
 
                dev_dbg(dev, "ss_version: 0x%08x\n", gbe_dev->ss_version);
 
@@ -2857,22 +2873,20 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
                else
                        ret = -ENODEV;
 
-               if (ret)
-                       goto quit;
        } else if (!strcmp(node->name, "xgbe")) {
                ret = set_xgbe_ethss10_priv(gbe_dev, node);
                if (ret)
-                       goto quit;
+                       return ret;
                ret = netcp_xgbe_serdes_init(gbe_dev->xgbe_serdes_regs,
                                             gbe_dev->ss_regs);
-               if (ret)
-                       goto quit;
        } else {
                dev_err(dev, "unknown GBE node(%s)\n", node->name);
                ret = -ENODEV;
-               goto quit;
        }
 
+       if (ret)
+               return ret;
+
        interfaces = of_get_child_by_name(node, "interfaces");
        if (!interfaces)
                dev_err(dev, "could not find interfaces\n");
@@ -2880,11 +2894,11 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
        ret = netcp_txpipe_init(&gbe_dev->tx_pipe, netcp_device,
                                gbe_dev->dma_chan_name, gbe_dev->tx_queue_id);
        if (ret)
-               goto quit;
+               return ret;
 
        ret = netcp_txpipe_open(&gbe_dev->tx_pipe);
        if (ret)
-               goto quit;
+               return ret;
 
        /* Create network interfaces */
        INIT_LIST_HEAD(&gbe_dev->gbe_intf_head);
@@ -2899,6 +2913,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
                if (gbe_dev->num_slaves >= gbe_dev->max_num_slaves)
                        break;
        }
+       of_node_put(interfaces);
 
        if (!gbe_dev->num_slaves)
                dev_warn(dev, "No network interface configured\n");
@@ -2911,9 +2926,10 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
        of_node_put(secondary_ports);
 
        if (!gbe_dev->num_slaves) {
-               dev_err(dev, "No network interface or secondary ports configured\n");
+               dev_err(dev,
+                       "No network interface or secondary ports configured\n");
                ret = -ENODEV;
-               goto quit;
+               goto free_sec_ports;
        }
 
        memset(&ale_params, 0, sizeof(ale_params));
@@ -2927,7 +2943,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
        if (!gbe_dev->ale) {
                dev_err(gbe_dev->dev, "error initializing ale engine\n");
                ret = -ENODEV;
-               goto quit;
+               goto free_sec_ports;
        } else {
                dev_dbg(gbe_dev->dev, "Created a gbe ale engine\n");
        }
@@ -2943,14 +2959,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
        *inst_priv = gbe_dev;
        return 0;
 
-quit:
-       if (gbe_dev->hw_stats)
-               devm_kfree(dev, gbe_dev->hw_stats);
-       cpsw_ale_destroy(gbe_dev->ale);
-       if (gbe_dev->ss_regs)
-               devm_iounmap(dev, gbe_dev->ss_regs);
-       of_node_put(interfaces);
-       devm_kfree(dev, gbe_dev);
+free_sec_ports:
+       free_secondary_ports(gbe_dev);
        return ret;
 }
 
@@ -3023,12 +3033,9 @@ static int gbe_remove(struct netcp_device *netcp_device, void *inst_priv)
        free_secondary_ports(gbe_dev);
 
        if (!list_empty(&gbe_dev->gbe_intf_head))
-               dev_alert(gbe_dev->dev, "unreleased ethss interfaces present\n");
+               dev_alert(gbe_dev->dev,
+                         "unreleased ethss interfaces present\n");
 
-       devm_kfree(gbe_dev->dev, gbe_dev->hw_stats);
-       devm_iounmap(gbe_dev->dev, gbe_dev->ss_regs);
-       memset(gbe_dev, 0x00, sizeof(*gbe_dev));
-       devm_kfree(gbe_dev->dev, gbe_dev);
        return 0;
 }
 
index dbeb14266e2fb106c8a16b7d32b73fbc28095ec7..5d8419f658d04397a7be30c2a1b9a249f492e6e8 100644 (file)
@@ -18,6 +18,9 @@
 
 #include "netcp.h"
 
+#define SGMII_SRESET_RESET             BIT(0)
+#define SGMII_SRESET_RTRESET           BIT(1)
+
 #define SGMII_REG_STATUS_LOCK          BIT(4)
 #define        SGMII_REG_STATUS_LINK           BIT(0)
 #define SGMII_REG_STATUS_AUTONEG       BIT(2)
@@ -51,12 +54,35 @@ static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val)
 int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port)
 {
        /* Soft reset */
-       sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port), 0x1);
-       while (sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) != 0x0)
+       sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port),
+                           SGMII_SRESET_RESET);
+
+       while ((sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) &
+               SGMII_SRESET_RESET) != 0x0)
                ;
+
        return 0;
 }
 
+/* port is 0 based */
+bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set)
+{
+       u32 reg;
+       bool oldval;
+
+       /* Initiate a soft reset */
+       reg = sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port));
+       oldval = (reg & SGMII_SRESET_RTRESET) != 0x0;
+       if (set)
+               reg |= SGMII_SRESET_RTRESET;
+       else
+               reg &= ~SGMII_SRESET_RTRESET;
+       sgmii_write_reg(sgmii_ofs, SGMII_SRESET_REG(port), reg);
+       wmb();
+
+       return oldval;
+}
+
 int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port)
 {
        u32 status = 0, link = 0;
index 2ffbf13471d09ad4c27d8c70fbb4dd3145befa75..216bfd350169a9da723035876d152e89b17c8432 100644 (file)
@@ -728,11 +728,12 @@ static int mkiss_open(struct tty_struct *tty)
        dev->type = ARPHRD_AX25;
 
        /* Perform the low-level AX25 initialization. */
-       if ((err = ax_open(ax->dev))) {
+       err = ax_open(ax->dev);
+       if (err)
                goto out_free_netdev;
-       }
 
-       if (register_netdev(dev))
+       err = register_netdev(dev);
+       if (err)
                goto out_free_buffers;
 
        /* after register_netdev() - because else printk smashes the kernel */
index 953a97492fabf46eda9986ad713e4cc9ec4275dd..9542b7bac61afab0f4537d91f8cc004160521f85 100644 (file)
@@ -67,8 +67,6 @@ struct ipvl_dev {
        struct ipvl_port        *port;
        struct net_device       *phy_dev;
        struct list_head        addrs;
-       int                     ipv4cnt;
-       int                     ipv6cnt;
        struct ipvl_pcpu_stats  __percpu *pcpu_stats;
        DECLARE_BITMAP(mac_filters, IPVLAN_MAC_FILTER_SIZE);
        netdev_features_t       sfeatures;
@@ -106,6 +104,11 @@ static inline struct ipvl_port *ipvlan_port_get_rcu(const struct net_device *d)
        return rcu_dereference(d->rx_handler_data);
 }
 
+static inline struct ipvl_port *ipvlan_port_get_rcu_bh(const struct net_device *d)
+{
+       return rcu_dereference_bh(d->rx_handler_data);
+}
+
 static inline struct ipvl_port *ipvlan_port_get_rtnl(const struct net_device *d)
 {
        return rtnl_dereference(d->rx_handler_data);
@@ -124,5 +127,5 @@ struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
 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);
+void ipvlan_ht_addr_del(struct ipvl_addr *addr);
 #endif /* __IPVLAN_H */
index 8afbedad620d9ed27576dc6426878ae858979a51..207f62e8de9a93415cc76eb5fd75f987b3de53b6 100644 (file)
@@ -85,11 +85,9 @@ void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr)
                hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
 }
 
-void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync)
+void ipvlan_ht_addr_del(struct ipvl_addr *addr)
 {
        hlist_del_init_rcu(&addr->hlnode);
-       if (sync)
-               synchronize_rcu();
 }
 
 struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
@@ -531,7 +529,7 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
 int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ipvl_dev *ipvlan = netdev_priv(dev);
-       struct ipvl_port *port = ipvlan_port_get_rcu(ipvlan->phy_dev);
+       struct ipvl_port *port = ipvlan_port_get_rcu_bh(ipvlan->phy_dev);
 
        if (!port)
                goto out;
index 1acc283160d924e0754f3da99fc120c638c257a2..20b58bdecf7540100edc5522e74804e6a7544d95 100644 (file)
@@ -153,10 +153,9 @@ static int ipvlan_open(struct net_device *dev)
        else
                dev->flags &= ~IFF_NOARP;
 
-       if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
-               list_for_each_entry(addr, &ipvlan->addrs, anode)
-                       ipvlan_ht_addr_add(ipvlan, addr);
-       }
+       list_for_each_entry(addr, &ipvlan->addrs, anode)
+               ipvlan_ht_addr_add(ipvlan, addr);
+
        return dev_uc_add(phy_dev, phy_dev->dev_addr);
 }
 
@@ -171,10 +170,9 @@ static int ipvlan_stop(struct net_device *dev)
 
        dev_uc_del(phy_dev, phy_dev->dev_addr);
 
-       if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
-               list_for_each_entry(addr, &ipvlan->addrs, anode)
-                       ipvlan_ht_addr_del(addr, !dev->dismantle);
-       }
+       list_for_each_entry(addr, &ipvlan->addrs, anode)
+               ipvlan_ht_addr_del(addr);
+
        return 0;
 }
 
@@ -471,8 +469,6 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
        ipvlan->port = port;
        ipvlan->sfeatures = IPVLAN_FEATURES;
        INIT_LIST_HEAD(&ipvlan->addrs);
-       ipvlan->ipv4cnt = 0;
-       ipvlan->ipv6cnt = 0;
 
        /* TODO Probably put random address here to be presented to the
         * world but keep using the physical-dev address for the outgoing
@@ -508,12 +504,12 @@ static void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
        struct ipvl_dev *ipvlan = netdev_priv(dev);
        struct ipvl_addr *addr, *next;
 
-       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(&addr->anode);
-               }
+       list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) {
+               ipvlan_ht_addr_del(addr);
+               list_del(&addr->anode);
+               kfree_rcu(addr, rcu);
        }
+
        list_del_rcu(&ipvlan->pnode);
        unregister_netdevice_queue(dev, head);
        netdev_upper_dev_unlink(ipvlan->phy_dev, dev);
@@ -627,7 +623,7 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
        memcpy(&addr->ip6addr, ip6_addr, sizeof(struct in6_addr));
        addr->atype = IPVL_IPV6;
        list_add_tail(&addr->anode, &ipvlan->addrs);
-       ipvlan->ipv6cnt++;
+
        /* If the interface is not up, the address will be added to the hash
         * list by ipvlan_open.
         */
@@ -645,10 +641,8 @@ static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
        if (!addr)
                return;
 
-       ipvlan_ht_addr_del(addr, true);
+       ipvlan_ht_addr_del(addr);
        list_del(&addr->anode);
-       ipvlan->ipv6cnt--;
-       WARN_ON(ipvlan->ipv6cnt < 0);
        kfree_rcu(addr, rcu);
 
        return;
@@ -661,6 +655,10 @@ static int ipvlan_addr6_event(struct notifier_block *unused,
        struct net_device *dev = (struct net_device *)if6->idev->dev;
        struct ipvl_dev *ipvlan = netdev_priv(dev);
 
+       /* FIXME IPv6 autoconf calls us from bh without RTNL */
+       if (in_softirq())
+               return NOTIFY_DONE;
+
        if (!netif_is_ipvlan(dev))
                return NOTIFY_DONE;
 
@@ -699,7 +697,7 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
        memcpy(&addr->ip4addr, ip4_addr, sizeof(struct in_addr));
        addr->atype = IPVL_IPV4;
        list_add_tail(&addr->anode, &ipvlan->addrs);
-       ipvlan->ipv4cnt++;
+
        /* If the interface is not up, the address will be added to the hash
         * list by ipvlan_open.
         */
@@ -717,10 +715,8 @@ static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
        if (!addr)
                return;
 
-       ipvlan_ht_addr_del(addr, true);
+       ipvlan_ht_addr_del(addr);
        list_del(&addr->anode);
-       ipvlan->ipv4cnt--;
-       WARN_ON(ipvlan->ipv4cnt < 0);
        kfree_rcu(addr, rcu);
 
        return;
index 3b933bb5a8d5084208c2a9903ab44317cae5d146..edd77342773a8d4ef0713717adfa5bcf6bdf44f7 100644 (file)
@@ -719,6 +719,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
        struct virtio_net_hdr vnet_hdr = { 0 };
        int vnet_hdr_len = 0;
        int copylen = 0;
+       int depth;
        bool zerocopy = false;
        size_t linear;
        ssize_t n;
@@ -804,6 +805,12 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
 
        skb_probe_transport_header(skb, ETH_HLEN);
 
+       /* Move network header to the right position for VLAN tagged packets */
+       if ((skb->protocol == htons(ETH_P_8021Q) ||
+            skb->protocol == htons(ETH_P_8021AD)) &&
+           __vlan_get_protocol(skb, skb->protocol, &depth) != 0)
+               skb_set_network_header(skb, depth);
+
        rcu_read_lock();
        vlan = rcu_dereference(q->vlan);
        /* copy skb_ubuf_info for callback when skb has no error */
index 3cc316cb7e6be792b06dfc2c520eae9809f1008b..d8757bf9ad755ed6a3114d9d0a9664e59618744a 100644 (file)
@@ -102,6 +102,12 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
 
        netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len);
 
+       if (len < 0) {
+               ndev->stats.rx_errors++;
+               ndev->stats.rx_length_errors++;
+               goto enqueue_again;
+       }
+
        skb_put(skb, len);
        skb->protocol = eth_type_trans(skb, ndev);
        skb->ip_summed = CHECKSUM_NONE;
@@ -121,6 +127,7 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
                return;
        }
 
+enqueue_again:
        rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
        if (rc) {
                dev_kfree_skb(skb);
@@ -184,7 +191,7 @@ static int ntb_netdev_open(struct net_device *ndev)
 
                rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
                                              ndev->mtu + ETH_HLEN);
-               if (rc == -EINVAL) {
+               if (rc) {
                        dev_kfree_skb(skb);
                        goto err;
                }
index c7a12e2e07b7670a55a682ea2988cc4cca86d7b7..8a3bf546989212734aa9a5a5a5b58948ecf264da 100644 (file)
@@ -164,7 +164,7 @@ static int dp83867_config_init(struct phy_device *phydev)
                        return ret;
        }
 
-       if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) ||
+       if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) &&
            (phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) {
                val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
                                            DP83867_DEVADDR, phydev->addr);
index 095ef3fe369af5ebe08254384abc38176df1aef1..46a14cbb021541095a22016a7ad712d79db9307a 100644 (file)
@@ -421,6 +421,8 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct phy_device *phydev = to_phy_device(dev);
        struct phy_driver *phydrv = to_phy_driver(drv);
+       const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids);
+       int i;
 
        if (of_driver_match_device(dev, drv))
                return 1;
@@ -428,8 +430,21 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
        if (phydrv->match_phy_device)
                return phydrv->match_phy_device(phydev);
 
-       return (phydrv->phy_id & phydrv->phy_id_mask) ==
-               (phydev->phy_id & phydrv->phy_id_mask);
+       if (phydev->is_c45) {
+               for (i = 1; i < num_ids; i++) {
+                       if (!(phydev->c45_ids.devices_in_package & (1 << i)))
+                               continue;
+
+                       if ((phydrv->phy_id & phydrv->phy_id_mask) ==
+                           (phydev->c45_ids.device_ids[i] &
+                            phydrv->phy_id_mask))
+                               return 1;
+               }
+               return 0;
+       } else {
+               return (phydrv->phy_id & phydrv->phy_id_mask) ==
+                       (phydev->phy_id & phydrv->phy_id_mask);
+       }
 }
 
 #ifdef CONFIG_PM
index f603f362504bce0c1cb2656e1d29232eb05db846..9d43460ce3c71f0b54c69b84fa5a0ec8b7341d5f 100644 (file)
@@ -757,6 +757,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1199, 0x901c, 8)},    /* Sierra Wireless EM7700 */
        {QMI_FIXED_INTF(0x1199, 0x901f, 8)},    /* Sierra Wireless EM7355 */
        {QMI_FIXED_INTF(0x1199, 0x9041, 8)},    /* Sierra Wireless MC7305/MC7355 */
+       {QMI_FIXED_INTF(0x1199, 0x9041, 10)},   /* Sierra Wireless MC7305/MC7355 */
        {QMI_FIXED_INTF(0x1199, 0x9051, 8)},    /* Netgear AirCard 340U */
        {QMI_FIXED_INTF(0x1199, 0x9053, 8)},    /* Sierra Wireless Modem */
        {QMI_FIXED_INTF(0x1199, 0x9054, 8)},    /* Sierra Wireless Modem */
index 7f6419ebb5e1cd8c7fc5abbe10170a4ad6d92ea8..ad8cbc6c9ee73513d7bc063ca8d41d75abce3038 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/usb/cdc.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v1.08.0 (2015/01/13)"
+#define DRIVER_VERSION "v1.08.1 (2015/07/28)"
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
 #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
 #define MODULENAME "r8152"
@@ -1902,11 +1902,10 @@ static void rtl_drop_queued_tx(struct r8152 *tp)
 static void rtl8152_tx_timeout(struct net_device *netdev)
 {
        struct r8152 *tp = netdev_priv(netdev);
-       int i;
 
        netif_warn(tp, tx_err, netdev, "Tx timeout\n");
-       for (i = 0; i < RTL8152_MAX_TX; i++)
-               usb_unlink_urb(tp->tx_info[i].urb);
+
+       usb_queue_reset_device(tp->intf);
 }
 
 static void rtl8152_set_rx_mode(struct net_device *netdev)
@@ -2075,7 +2074,6 @@ static int rtl_start_rx(struct r8152 *tp)
 {
        int i, ret = 0;
 
-       napi_disable(&tp->napi);
        INIT_LIST_HEAD(&tp->rx_done);
        for (i = 0; i < RTL8152_MAX_RX; i++) {
                INIT_LIST_HEAD(&tp->rx_info[i].list);
@@ -2083,7 +2081,6 @@ static int rtl_start_rx(struct r8152 *tp)
                if (ret)
                        break;
        }
-       napi_enable(&tp->napi);
 
        if (ret && ++i < RTL8152_MAX_RX) {
                struct list_head rx_queue;
@@ -2166,6 +2163,7 @@ static int rtl8153_enable(struct r8152 *tp)
        if (test_bit(RTL8152_UNPLUG, &tp->flags))
                return -ENODEV;
 
+       usb_disable_lpm(tp->udev);
        set_tx_qlen(tp);
        rtl_set_eee_plus(tp);
        r8153_set_rx_early_timeout(tp);
@@ -2337,11 +2335,61 @@ static void __rtl_set_wol(struct r8152 *tp, u32 wolopts)
                device_set_wakeup_enable(&tp->udev->dev, false);
 }
 
+static void r8153_u1u2en(struct r8152 *tp, bool enable)
+{
+       u8 u1u2[8];
+
+       if (enable)
+               memset(u1u2, 0xff, sizeof(u1u2));
+       else
+               memset(u1u2, 0x00, sizeof(u1u2));
+
+       usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
+}
+
+static void r8153_u2p3en(struct r8152 *tp, bool enable)
+{
+       u32 ocp_data;
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL);
+       if (enable && tp->version != RTL_VER_03 && tp->version != RTL_VER_04)
+               ocp_data |= U2P3_ENABLE;
+       else
+               ocp_data &= ~U2P3_ENABLE;
+       ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
+}
+
+static void r8153_power_cut_en(struct r8152 *tp, bool enable)
+{
+       u32 ocp_data;
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT);
+       if (enable)
+               ocp_data |= PWR_EN | PHASE2_EN;
+       else
+               ocp_data &= ~(PWR_EN | PHASE2_EN);
+       ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
+       ocp_data &= ~PCUT_STATUS;
+       ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
+}
+
+static bool rtl_can_wakeup(struct r8152 *tp)
+{
+       struct usb_device *udev = tp->udev;
+
+       return (udev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_WAKEUP);
+}
+
 static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable)
 {
        if (enable) {
                u32 ocp_data;
 
+               r8153_u1u2en(tp, false);
+               r8153_u2p3en(tp, false);
+
                __rtl_set_wol(tp, WAKE_ANY);
 
                ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
@@ -2353,6 +2401,8 @@ static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable)
                ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
        } else {
                __rtl_set_wol(tp, tp->saved_wolopts);
+               r8153_u2p3en(tp, true);
+               r8153_u1u2en(tp, true);
        }
 }
 
@@ -2599,46 +2649,6 @@ static void r8153_hw_phy_cfg(struct r8152 *tp)
        set_bit(PHY_RESET, &tp->flags);
 }
 
-static void r8153_u1u2en(struct r8152 *tp, bool enable)
-{
-       u8 u1u2[8];
-
-       if (enable)
-               memset(u1u2, 0xff, sizeof(u1u2));
-       else
-               memset(u1u2, 0x00, sizeof(u1u2));
-
-       usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
-}
-
-static void r8153_u2p3en(struct r8152 *tp, bool enable)
-{
-       u32 ocp_data;
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL);
-       if (enable)
-               ocp_data |= U2P3_ENABLE;
-       else
-               ocp_data &= ~U2P3_ENABLE;
-       ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
-}
-
-static void r8153_power_cut_en(struct r8152 *tp, bool enable)
-{
-       u32 ocp_data;
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT);
-       if (enable)
-               ocp_data |= PWR_EN | PHASE2_EN;
-       else
-               ocp_data &= ~(PWR_EN | PHASE2_EN);
-       ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
-       ocp_data &= ~PCUT_STATUS;
-       ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
-}
-
 static void r8153_first_init(struct r8152 *tp)
 {
        u32 ocp_data;
@@ -2781,6 +2791,7 @@ static void rtl8153_disable(struct r8152 *tp)
        r8153_disable_aldps(tp);
        rtl_disable(tp);
        r8153_enable_aldps(tp);
+       usb_enable_lpm(tp->udev);
 }
 
 static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
@@ -2901,9 +2912,13 @@ static void rtl8153_up(struct r8152 *tp)
        if (test_bit(RTL8152_UNPLUG, &tp->flags))
                return;
 
+       r8153_u1u2en(tp, false);
        r8153_disable_aldps(tp);
        r8153_first_init(tp);
        r8153_enable_aldps(tp);
+       r8153_u2p3en(tp, true);
+       r8153_u1u2en(tp, true);
+       usb_enable_lpm(tp->udev);
 }
 
 static void rtl8153_down(struct r8152 *tp)
@@ -2914,6 +2929,7 @@ static void rtl8153_down(struct r8152 *tp)
        }
 
        r8153_u1u2en(tp, false);
+       r8153_u2p3en(tp, false);
        r8153_power_cut_en(tp, false);
        r8153_disable_aldps(tp);
        r8153_enter_oob(tp);
@@ -2932,8 +2948,10 @@ static void set_carrier(struct r8152 *tp)
                if (!netif_carrier_ok(netdev)) {
                        tp->rtl_ops.enable(tp);
                        set_bit(RTL8152_SET_RX_MODE, &tp->flags);
+                       napi_disable(&tp->napi);
                        netif_carrier_on(netdev);
                        rtl_start_rx(tp);
+                       napi_enable(&tp->napi);
                }
        } else {
                if (netif_carrier_ok(netdev)) {
@@ -3252,6 +3270,7 @@ static void r8153_init(struct r8152 *tp)
                msleep(20);
        }
 
+       usb_disable_lpm(tp->udev);
        r8153_u2p3en(tp, false);
 
        if (tp->version == RTL_VER_04) {
@@ -3319,6 +3338,59 @@ static void r8153_init(struct r8152 *tp)
        r8153_enable_aldps(tp);
        r8152b_enable_fc(tp);
        rtl_tally_reset(tp);
+       r8153_u2p3en(tp, true);
+}
+
+static int rtl8152_pre_reset(struct usb_interface *intf)
+{
+       struct r8152 *tp = usb_get_intfdata(intf);
+       struct net_device *netdev;
+
+       if (!tp)
+               return 0;
+
+       netdev = tp->netdev;
+       if (!netif_running(netdev))
+               return 0;
+
+       napi_disable(&tp->napi);
+       clear_bit(WORK_ENABLE, &tp->flags);
+       usb_kill_urb(tp->intr_urb);
+       cancel_delayed_work_sync(&tp->schedule);
+       if (netif_carrier_ok(netdev)) {
+               netif_stop_queue(netdev);
+               mutex_lock(&tp->control);
+               tp->rtl_ops.disable(tp);
+               mutex_unlock(&tp->control);
+       }
+
+       return 0;
+}
+
+static int rtl8152_post_reset(struct usb_interface *intf)
+{
+       struct r8152 *tp = usb_get_intfdata(intf);
+       struct net_device *netdev;
+
+       if (!tp)
+               return 0;
+
+       netdev = tp->netdev;
+       if (!netif_running(netdev))
+               return 0;
+
+       set_bit(WORK_ENABLE, &tp->flags);
+       if (netif_carrier_ok(netdev)) {
+               mutex_lock(&tp->control);
+               tp->rtl_ops.enable(tp);
+               rtl8152_set_rx_mode(netdev);
+               mutex_unlock(&tp->control);
+               netif_wake_queue(netdev);
+       }
+
+       napi_enable(&tp->napi);
+
+       return 0;
 }
 
 static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
@@ -3374,9 +3446,11 @@ static int rtl8152_resume(struct usb_interface *intf)
                if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
                        rtl_runtime_suspend_enable(tp, false);
                        clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+                       napi_disable(&tp->napi);
                        set_bit(WORK_ENABLE, &tp->flags);
                        if (netif_carrier_ok(tp->netdev))
                                rtl_start_rx(tp);
+                       napi_enable(&tp->napi);
                } else {
                        tp->rtl_ops.up(tp);
                        rtl8152_set_speed(tp, AUTONEG_ENABLE,
@@ -3403,12 +3477,15 @@ static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (usb_autopm_get_interface(tp->intf) < 0)
                return;
 
-       mutex_lock(&tp->control);
-
-       wol->supported = WAKE_ANY;
-       wol->wolopts = __rtl_get_wol(tp);
-
-       mutex_unlock(&tp->control);
+       if (!rtl_can_wakeup(tp)) {
+               wol->supported = 0;
+               wol->wolopts = 0;
+       } else {
+               mutex_lock(&tp->control);
+               wol->supported = WAKE_ANY;
+               wol->wolopts = __rtl_get_wol(tp);
+               mutex_unlock(&tp->control);
+       }
 
        usb_autopm_put_interface(tp->intf);
 }
@@ -3418,6 +3495,9 @@ static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        struct r8152 *tp = netdev_priv(dev);
        int ret;
 
+       if (!rtl_can_wakeup(tp))
+               return -EOPNOTSUPP;
+
        ret = usb_autopm_get_interface(tp->intf);
        if (ret < 0)
                goto out_set_wol;
@@ -4059,6 +4139,9 @@ static int rtl8152_probe(struct usb_interface *intf,
                goto out1;
        }
 
+       if (!rtl_can_wakeup(tp))
+               __rtl_set_wol(tp, 0);
+
        tp->saved_wolopts = __rtl_get_wol(tp);
        if (tp->saved_wolopts)
                device_set_wakeup_enable(&udev->dev, true);
@@ -4132,6 +4215,8 @@ static struct usb_driver rtl8152_driver = {
        .suspend =      rtl8152_suspend,
        .resume =       rtl8152_resume,
        .reset_resume = rtl8152_resume,
+       .pre_reset =    rtl8152_pre_reset,
+       .post_reset =   rtl8152_post_reset,
        .supports_autosuspend = 1,
        .disable_hub_initiated_lpm = 1,
 };
index 63c7810e1545a357eda7578af862ed18322de933..237f8e5e493ddaae958684e8ed411c6f7f2363d6 100644 (file)
@@ -1756,9 +1756,9 @@ static int virtnet_probe(struct virtio_device *vdev)
        /* Do we support "hardware" checksums? */
        if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
                /* This opens up the world of extra features. */
-               dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+               dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
                if (csum)
-                       dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+                       dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
 
                if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
                        dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO
@@ -1828,7 +1828,8 @@ static int virtnet_probe(struct virtio_device *vdev)
        else
                vi->hdr_len = sizeof(struct virtio_net_hdr);
 
-       if (virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT))
+       if (virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT) ||
+           virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
                vi->any_header_sg = true;
 
        if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
index 7193b7304fdd3ed4b69c0125732d4a024d4a4b36..848ea6a399f236b14cc5d9a79dd38038e0331aec 100644 (file)
@@ -589,7 +589,8 @@ static int cosa_probe(int base, int irq, int dma)
                chan->netdev->base_addr = chan->cosa->datareg;
                chan->netdev->irq = chan->cosa->irq;
                chan->netdev->dma = chan->cosa->dma;
-               if (register_hdlc_device(chan->netdev)) {
+               err = register_hdlc_device(chan->netdev);
+               if (err) {
                        netdev_warn(chan->netdev,
                                    "register_hdlc_device() failed\n");
                        free_netdev(chan->netdev);
index 5e15e8e10ed39f0b605783176fe260faa387d083..a31a6804dc34eff8174b06e15d8ee14bb5405888 100644 (file)
@@ -279,6 +279,7 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
                return;
        case AR9300_DEVID_QCA956X:
                ah->hw_version.macVersion = AR_SREV_VERSION_9561;
+               return;
        }
 
        val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
index 25d1cbd34306e03ea4827e09509c345d11b5a1df..b2f0d245bcf3a0e71fb96797c47f71ad0ca736db 100644 (file)
@@ -3728,7 +3728,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev)
                switch (phy->rev) {
                case 6:
                case 5:
-                       if (sprom->fem.ghz5.extpa_gain == 3)
+                       if (sprom->fem.ghz2.extpa_gain == 3)
                                return b43_ntab_tx_gain_epa_rev3_hi_pwr_2g;
                        /* fall through */
                case 4:
index d56064861a9c353dfb9fcf1720e1abde6c3fcf9d..d45dc021cda2c0715b8d7e740ff90b46589ae141 100644 (file)
@@ -438,6 +438,12 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
 #define RX_QUEUE_MASK                         255
 #define RX_QUEUE_SIZE_LOG                     8
 
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
 /**
  * struct iwl_rb_status - reserve buffer status
  *     host memory mapped FH registers
index 80fefe7d7b8cb3b46581b32f299fed425e878980..3b8e85e51002560a0a860db0999ec947c29fb0d2 100644 (file)
@@ -540,13 +540,11 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
                hw_addr = (const u8 *)(mac_override +
                                 MAC_ADDRESS_OVERRIDE_FAMILY_8000);
 
-               /* The byte order is little endian 16 bit, meaning 214365 */
-               data->hw_addr[0] = hw_addr[1];
-               data->hw_addr[1] = hw_addr[0];
-               data->hw_addr[2] = hw_addr[3];
-               data->hw_addr[3] = hw_addr[2];
-               data->hw_addr[4] = hw_addr[5];
-               data->hw_addr[5] = hw_addr[4];
+               /*
+                * Store the MAC address from MAO section.
+                * No byte swapping is required in MAO section
+                */
+               memcpy(data->hw_addr, hw_addr, ETH_ALEN);
 
                /*
                 * Force the use of the OTP MAC address in case of reserved MAC
index 5e4cbdb44c607ec8399bae489f28990dc907eaeb..737774a01c74a500b3934928449531889701d7f5 100644 (file)
@@ -660,7 +660,8 @@ struct iwl_scan_config {
  * iwl_umac_scan_flags
  *@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request
  *     can be preempted by other scan requests with higher priority.
- *     The low priority scan is aborted.
+ *     The low priority scan will be resumed when the higher proirity scan is
+ *     completed.
  *@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver
  *     when scan starts.
  */
index 5de144968723d4f2a5446f0d6f9fc0607baf2efb..5514ad6d4e54373d2a48564ec790489dfe1808dc 100644 (file)
@@ -1023,7 +1023,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
        cmd->scan_priority =
                iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
 
-       if (iwl_mvm_scan_total_iterations(params) == 0)
+       if (iwl_mvm_scan_total_iterations(params) == 1)
                cmd->ooc_priority =
                        iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
        else
@@ -1109,6 +1109,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        cmd->uid = cpu_to_le32(uid);
        cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params));
 
+       if (type == IWL_MVM_SCAN_SCHED)
+               cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
+
        if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations))
                cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
                                     IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
index d68dc697a4a06ef2b9c786de0fc98f3e5fe35544..26f076e821491e09d7805c5f37d229d01480229c 100644 (file)
@@ -1401,6 +1401,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
        bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
        u8 sta_id;
        int ret;
+       static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0};
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -1467,7 +1468,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
 end:
        IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
                      keyconf->cipher, keyconf->keylen, keyconf->keyidx,
-                     sta->addr, ret);
+                     sta ? sta->addr : zero_addr, ret);
        return ret;
 }
 
index d24b6a83e68cfcd4281301c907cb62a24661da96..e472729e5f149a451fd7128d45fa54856c8a77ce 100644 (file)
@@ -86,7 +86,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
 {
        lockdep_assert_held(&mvm->time_event_lock);
 
-       if (te_data->id == TE_MAX)
+       if (!te_data->vif)
                return;
 
        list_del(&te_data->list);
index 7ba7a118ff5ca28615f5ceeb745f577999ea52dc..89116864d2a0ec346941ec8e4fded14691612ff3 100644 (file)
@@ -252,7 +252,7 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,
 
        if (info->band == IEEE80211_BAND_2GHZ &&
            !iwl_mvm_bt_coex_is_shared_ant_avail(mvm))
-               rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS;
+               rate_flags = mvm->cfg->non_shared_ant << RATE_MCS_ANT_POS;
        else
                rate_flags =
                        BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
index 2ed1e4d2774da83f1cd609983c8383c48d37a128..9f65c1cff1b1958057ab3bedf385604b34a3323e 100644 (file)
@@ -368,12 +368,14 @@ 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(0x3166, 0x4212, 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)},
+       {IWL_PCI_DEVICE(0x3165, 0x8110, iwl3165_2ac_cfg)},
 
 /* 7265 Series */
        {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
@@ -426,9 +428,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x24F4, 0x1130, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0xC110, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x24F4, 0xC030, iwl8260_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x24F4, 0xD030, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)},
index 31f72a61cc3fe06b6d9189f718cc3315677625ad..376b84e54ad7e8bbb48d039d354c03748665451c 100644 (file)
 #include "iwl-io.h"
 #include "iwl-op-mode.h"
 
-/*
- * RX related structures and functions
- */
-#define RX_NUM_QUEUES 1
-#define RX_POST_REQ_ALLOC 2
-#define RX_CLAIM_REQ_ALLOC 8
-#define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES)
-#define RX_LOW_WATERMARK 8
-
 struct iwl_host_cmd;
 
 /*This file includes the declaration that are internal to the
@@ -86,29 +77,29 @@ struct isr_statistics {
  * struct iwl_rxq - Rx queue
  * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
  * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
+ * @pool:
+ * @queue:
  * @read: Shared index to newest available Rx buffer
  * @write: Shared index to oldest written Rx packet
  * @free_count: Number of pre-allocated buffers in rx_free
- * @used_count: Number of RBDs handled to allocator to use for allocation
  * @write_actual:
- * @rx_free: list of RBDs with allocated RB ready for use
- * @rx_used: list of RBDs with no RB attached
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
  * @need_update: flag to indicate we need to update read/write index
  * @rb_stts: driver's pointer to receive buffer status
  * @rb_stts_dma: bus address of receive buffer status
  * @lock:
- * @pool: initial pool of iwl_rx_mem_buffer for the queue
- * @queue: actual rx queue
  *
  * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
  */
 struct iwl_rxq {
        __le32 *bd;
        dma_addr_t bd_dma;
+       struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+       struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
        u32 read;
        u32 write;
        u32 free_count;
-       u32 used_count;
        u32 write_actual;
        struct list_head rx_free;
        struct list_head rx_used;
@@ -116,32 +107,6 @@ struct iwl_rxq {
        struct iwl_rb_status *rb_stts;
        dma_addr_t rb_stts_dma;
        spinlock_t lock;
-       struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE];
-       struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
-};
-
-/**
- * struct iwl_rb_allocator - Rx allocator
- * @pool: initial pool of allocator
- * @req_pending: number of requests the allcator had not processed yet
- * @req_ready: number of requests honored and ready for claiming
- * @rbd_allocated: RBDs with pages allocated and ready to be handled to
- *     the queue. This is a list of &struct iwl_rx_mem_buffer
- * @rbd_empty: RBDs with no page attached for allocator use. This is a list
- *     of &struct iwl_rx_mem_buffer
- * @lock: protects the rbd_allocated and rbd_empty lists
- * @alloc_wq: work queue for background calls
- * @rx_alloc: work struct for background calls
- */
-struct iwl_rb_allocator {
-       struct iwl_rx_mem_buffer pool[RX_POOL_SIZE];
-       atomic_t req_pending;
-       atomic_t req_ready;
-       struct list_head rbd_allocated;
-       struct list_head rbd_empty;
-       spinlock_t lock;
-       struct workqueue_struct *alloc_wq;
-       struct work_struct rx_alloc;
 };
 
 struct iwl_dma_ptr {
@@ -285,7 +250,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
 /**
  * struct iwl_trans_pcie - PCIe transport specific data
  * @rxq: all the RX queue data
- * @rba: allocator for RX replenishing
+ * @rx_replenish: work that will be called when buffers need to be allocated
  * @drv - pointer to iwl_drv
  * @trans: pointer to the generic transport area
  * @scd_base_addr: scheduler sram base address in SRAM
@@ -308,7 +273,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
  */
 struct iwl_trans_pcie {
        struct iwl_rxq rxq;
-       struct iwl_rb_allocator rba;
+       struct work_struct rx_replenish;
        struct iwl_trans *trans;
        struct iwl_drv *drv;
 
index a3fbaa0ef5e04de7d1032c79ca35e82364dac7ea..adad8d0fae7f2766812826377c46d29f1f77d4ed 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
  * resets the Rx queue buffers with new memory.
  *
  * The management in the driver is as follows:
- * + A list of pre-allocated RBDs is stored in iwl->rxq->rx_free.
- *   When the interrupt handler is called, the request is processed.
- *   The page is either stolen - transferred to the upper layer
- *   or reused - added immediately to the iwl->rxq->rx_free list.
- * + When the page is stolen - the driver updates the matching queue's used
- *   count, detaches the RBD and transfers it to the queue used list.
- *   When there are two used RBDs - they are transferred to the allocator empty
- *   list. Work is then scheduled for the allocator to start allocating
- *   eight buffers.
- *   When there are another 6 used RBDs - they are transferred to the allocator
- *   empty list and the driver tries to claim the pre-allocated buffers and
- *   add them to iwl->rxq->rx_free. If it fails - it continues to claim them
- *   until ready.
- *   When there are 8+ buffers in the free list - either from allocation or from
- *   8 reused unstolen pages - restock is called to update the FW and indexes.
- * + In order to make sure the allocator always has RBDs to use for allocation
- *   the allocator has initial pool in the size of num_queues*(8-2) - the
- *   maximum missing RBDs per allocation request (request posted with 2
- *    empty RBDs, there is no guarantee when the other 6 RBDs are supplied).
- *   The queues supplies the recycle of the rest of the RBDs.
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
+ *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ *   to replenish the iwl->rxq->rx_free.
+ * + In iwl_pcie_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   iwl->rxq is replenished and the READ INDEX is updated (updating the
+ *   'processed' and 'read' driver indexes as well)
  * + A received packet is processed and handed to the kernel network stack,
  *   detached from the iwl->rxq.  The driver 'processed' index is updated.
- * + If there are no allocated buffers in iwl->rxq->rx_free,
+ * + The Host/Firmware iwl->rxq is replenished at irq thread time from the
+ *   rx_free list. If there are no allocated buffers in iwl->rxq->rx_free,
  *   the READ INDEX is not incremented and iwl->status(RX_STALLED) is set.
  *   If there were enough free buffers and RX_STALLED is set it is cleared.
  *
  *
  * iwl_rxq_alloc()            Allocates rx_free
  * iwl_pcie_rx_replenish()    Replenishes rx_free list from rx_used, and calls
- *                            iwl_pcie_rxq_restock.
- *                            Used only during initialization.
+ *                            iwl_pcie_rxq_restock
  * iwl_pcie_rxq_restock()     Moves available buffers from rx_free into Rx
  *                            queue, updates firmware pointers, and updates
- *                            the WRITE index.
- * iwl_pcie_rx_allocator()     Background work for allocating pages.
+ *                            the WRITE index.  If insufficient rx_free buffers
+ *                            are available, schedules iwl_pcie_rx_replenish
  *
  * -- enable interrupts --
  * ISR - iwl_rx()             Detach iwl_rx_mem_buffers from pool up to the
  *                            READ INDEX, detaching the SKB from the pool.
  *                            Moves the packet buffer from queue to rx_used.
- *                            Posts and claims requests to the allocator.
  *                            Calls iwl_pcie_rxq_restock to refill any empty
  *                            slots.
- *
- * RBD life-cycle:
- *
- * Init:
- * rxq.pool -> rxq.rx_used -> rxq.rx_free -> rxq.queue
- *
- * Regular Receive interrupt:
- * Page Stolen:
- * rxq.queue -> rxq.rx_used -> allocator.rbd_empty ->
- * allocator.rbd_allocated -> rxq.rx_free -> rxq.queue
- * Page not Stolen:
- * rxq.queue -> rxq.rx_free -> rxq.queue
  * ...
  *
  */
@@ -267,6 +240,10 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
                rxq->free_count--;
        }
        spin_unlock(&rxq->lock);
+       /* If the pre-allocated buffer pool is dropping low, schedule to
+        * refill it */
+       if (rxq->free_count <= RX_LOW_WATERMARK)
+               schedule_work(&trans_pcie->rx_replenish);
 
        /* If we've added more space for the firmware to place data, tell it.
         * Increment device's write pointer in multiples of 8. */
@@ -277,44 +254,6 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
        }
 }
 
-/*
- * iwl_pcie_rx_alloc_page - allocates and returns a page.
- *
- */
-static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
-       struct page *page;
-       gfp_t gfp_mask = GFP_KERNEL;
-
-       if (rxq->free_count > RX_LOW_WATERMARK)
-               gfp_mask |= __GFP_NOWARN;
-
-       if (trans_pcie->rx_page_order > 0)
-               gfp_mask |= __GFP_COMP;
-
-       /* Alloc a new receive buffer */
-       page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
-       if (!page) {
-               if (net_ratelimit())
-                       IWL_DEBUG_INFO(trans, "alloc_pages failed, order: %d\n",
-                                      trans_pcie->rx_page_order);
-               /* Issue an error if the hardware has consumed more than half
-                * of its free buffer list and we don't have enough
-                * pre-allocated buffers.
-`               */
-               if (rxq->free_count <= RX_LOW_WATERMARK &&
-                   iwl_rxq_space(rxq) > (RX_QUEUE_SIZE / 2) &&
-                   net_ratelimit())
-                       IWL_CRIT(trans,
-                                "Failed to alloc_pages with GFP_KERNEL. Only %u free buffers remaining.\n",
-                                rxq->free_count);
-               return NULL;
-       }
-       return page;
-}
-
 /*
  * iwl_pcie_rxq_alloc_rbs - allocate a page for each used RBD
  *
@@ -324,12 +263,13 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans)
  * iwl_pcie_rxq_restock. The latter function will update the HW to use the newly
  * allocated buffers.
  */
-static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans)
+static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
        struct page *page;
+       gfp_t gfp_mask = priority;
 
        while (1) {
                spin_lock(&rxq->lock);
@@ -339,10 +279,32 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans)
                }
                spin_unlock(&rxq->lock);
 
+               if (rxq->free_count > RX_LOW_WATERMARK)
+                       gfp_mask |= __GFP_NOWARN;
+
+               if (trans_pcie->rx_page_order > 0)
+                       gfp_mask |= __GFP_COMP;
+
                /* Alloc a new receive buffer */
-               page = iwl_pcie_rx_alloc_page(trans);
-               if (!page)
+               page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
+               if (!page) {
+                       if (net_ratelimit())
+                               IWL_DEBUG_INFO(trans, "alloc_pages failed, "
+                                          "order: %d\n",
+                                          trans_pcie->rx_page_order);
+
+                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+                           net_ratelimit())
+                               IWL_CRIT(trans, "Failed to alloc_pages with %s."
+                                        "Only %u free buffers remaining.\n",
+                                        priority == GFP_ATOMIC ?
+                                        "GFP_ATOMIC" : "GFP_KERNEL",
+                                        rxq->free_count);
+                       /* We don't reschedule replenish work here -- we will
+                        * call the restock method and if it still needs
+                        * more buffers it will schedule replenish */
                        return;
+               }
 
                spin_lock(&rxq->lock);
 
@@ -393,7 +355,7 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
 
        lockdep_assert_held(&rxq->lock);
 
-       for (i = 0; i < RX_QUEUE_SIZE; i++) {
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
                if (!rxq->pool[i].page)
                        continue;
                dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
@@ -410,144 +372,32 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
  * When moving to rx_free an page is allocated for the slot.
  *
  * Also restock the Rx queue via iwl_pcie_rxq_restock.
- * This is called only during initialization
+ * This is called as a scheduled work item (except for during initialization)
  */
-static void iwl_pcie_rx_replenish(struct iwl_trans *trans)
+static void iwl_pcie_rx_replenish(struct iwl_trans *trans, gfp_t gfp)
 {
-       iwl_pcie_rxq_alloc_rbs(trans);
+       iwl_pcie_rxq_alloc_rbs(trans, gfp);
 
        iwl_pcie_rxq_restock(trans);
 }
 
-/*
- * iwl_pcie_rx_allocator - Allocates pages in the background for RX queues
- *
- * Allocates for each received request 8 pages
- * Called as a scheduled work item.
- */
-static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-
-       while (atomic_read(&rba->req_pending)) {
-               int i;
-               struct list_head local_empty;
-               struct list_head local_allocated;
-
-               INIT_LIST_HEAD(&local_allocated);
-               spin_lock(&rba->lock);
-               /* swap out the entire rba->rbd_empty to a local list */
-               list_replace_init(&rba->rbd_empty, &local_empty);
-               spin_unlock(&rba->lock);
-
-               for (i = 0; i < RX_CLAIM_REQ_ALLOC;) {
-                       struct iwl_rx_mem_buffer *rxb;
-                       struct page *page;
-
-                       /* List should never be empty - each reused RBD is
-                        * returned to the list, and initial pool covers any
-                        * possible gap between the time the page is allocated
-                        * to the time the RBD is added.
-                        */
-                       BUG_ON(list_empty(&local_empty));
-                       /* Get the first rxb from the rbd list */
-                       rxb = list_first_entry(&local_empty,
-                                              struct iwl_rx_mem_buffer, list);
-                       BUG_ON(rxb->page);
-
-                       /* Alloc a new receive buffer */
-                       page = iwl_pcie_rx_alloc_page(trans);
-                       if (!page)
-                               continue;
-                       rxb->page = page;
-
-                       /* Get physical address of the RB */
-                       rxb->page_dma = dma_map_page(trans->dev, page, 0,
-                                       PAGE_SIZE << trans_pcie->rx_page_order,
-                                       DMA_FROM_DEVICE);
-                       if (dma_mapping_error(trans->dev, rxb->page_dma)) {
-                               rxb->page = NULL;
-                               __free_pages(page, trans_pcie->rx_page_order);
-                               continue;
-                       }
-                       /* dma address must be no more than 36 bits */
-                       BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-                       /* and also 256 byte aligned! */
-                       BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
-
-                       /* move the allocated entry to the out list */
-                       list_move(&rxb->list, &local_allocated);
-                       i++;
-               }
-
-               spin_lock(&rba->lock);
-               /* add the allocated rbds to the allocator allocated list */
-               list_splice_tail(&local_allocated, &rba->rbd_allocated);
-               /* add the unused rbds back to the allocator empty list */
-               list_splice_tail(&local_empty, &rba->rbd_empty);
-               spin_unlock(&rba->lock);
-
-               atomic_dec(&rba->req_pending);
-               atomic_inc(&rba->req_ready);
-       }
-}
-
-/*
- * iwl_pcie_rx_allocator_get - Returns the pre-allocated pages
-.*
-.* Called by queue when the queue posted allocation request and
- * has freed 8 RBDs in order to restock itself.
- */
-static int iwl_pcie_rx_allocator_get(struct iwl_trans *trans,
-                                    struct iwl_rx_mem_buffer
-                                    *out[RX_CLAIM_REQ_ALLOC])
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-       int i;
-
-       if (atomic_dec_return(&rba->req_ready) < 0) {
-               atomic_inc(&rba->req_ready);
-               IWL_DEBUG_RX(trans,
-                            "Allocation request not ready, pending requests = %d\n",
-                            atomic_read(&rba->req_pending));
-               return -ENOMEM;
-       }
-
-       spin_lock(&rba->lock);
-       for (i = 0; i < RX_CLAIM_REQ_ALLOC; i++) {
-               /* Get next free Rx buffer, remove it from free list */
-               out[i] = list_first_entry(&rba->rbd_allocated,
-                              struct iwl_rx_mem_buffer, list);
-               list_del(&out[i]->list);
-       }
-       spin_unlock(&rba->lock);
-
-       return 0;
-}
-
-static void iwl_pcie_rx_allocator_work(struct work_struct *data)
+static void iwl_pcie_rx_replenish_work(struct work_struct *data)
 {
-       struct iwl_rb_allocator *rba_p =
-               container_of(data, struct iwl_rb_allocator, rx_alloc);
        struct iwl_trans_pcie *trans_pcie =
-               container_of(rba_p, struct iwl_trans_pcie, rba);
+           container_of(data, struct iwl_trans_pcie, rx_replenish);
 
-       iwl_pcie_rx_allocator(trans_pcie->trans);
+       iwl_pcie_rx_replenish(trans_pcie->trans, GFP_KERNEL);
 }
 
 static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
        struct device *dev = trans->dev;
 
        memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
 
        spin_lock_init(&rxq->lock);
-       spin_lock_init(&rba->lock);
 
        if (WARN_ON(rxq->bd || rxq->rb_stts))
                return -EINVAL;
@@ -637,49 +487,15 @@ static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
        INIT_LIST_HEAD(&rxq->rx_free);
        INIT_LIST_HEAD(&rxq->rx_used);
        rxq->free_count = 0;
-       rxq->used_count = 0;
 
-       for (i = 0; i < RX_QUEUE_SIZE; i++)
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
                list_add(&rxq->pool[i].list, &rxq->rx_used);
 }
 
-static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba)
-{
-       int i;
-
-       lockdep_assert_held(&rba->lock);
-
-       INIT_LIST_HEAD(&rba->rbd_allocated);
-       INIT_LIST_HEAD(&rba->rbd_empty);
-
-       for (i = 0; i < RX_POOL_SIZE; i++)
-               list_add(&rba->pool[i].list, &rba->rbd_empty);
-}
-
-static void iwl_pcie_rx_free_rba(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-       int i;
-
-       lockdep_assert_held(&rba->lock);
-
-       for (i = 0; i < RX_POOL_SIZE; i++) {
-               if (!rba->pool[i].page)
-                       continue;
-               dma_unmap_page(trans->dev, rba->pool[i].page_dma,
-                              PAGE_SIZE << trans_pcie->rx_page_order,
-                              DMA_FROM_DEVICE);
-               __free_pages(rba->pool[i].page, trans_pcie->rx_page_order);
-               rba->pool[i].page = NULL;
-       }
-}
-
 int iwl_pcie_rx_init(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
        int i, err;
 
        if (!rxq->bd) {
@@ -687,21 +503,11 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
                if (err)
                        return err;
        }
-       if (!rba->alloc_wq)
-               rba->alloc_wq = alloc_workqueue("rb_allocator",
-                                               WQ_HIGHPRI | WQ_UNBOUND, 1);
-       INIT_WORK(&rba->rx_alloc, iwl_pcie_rx_allocator_work);
-
-       spin_lock(&rba->lock);
-       atomic_set(&rba->req_pending, 0);
-       atomic_set(&rba->req_ready, 0);
-       /* free all first - we might be reconfigured for a different size */
-       iwl_pcie_rx_free_rba(trans);
-       iwl_pcie_rx_init_rba(rba);
-       spin_unlock(&rba->lock);
 
        spin_lock(&rxq->lock);
 
+       INIT_WORK(&trans_pcie->rx_replenish, iwl_pcie_rx_replenish_work);
+
        /* free all first - we might be reconfigured for a different size */
        iwl_pcie_rxq_free_rbs(trans);
        iwl_pcie_rx_init_rxb_lists(rxq);
@@ -716,7 +522,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
        spin_unlock(&rxq->lock);
 
-       iwl_pcie_rx_replenish(trans);
+       iwl_pcie_rx_replenish(trans, GFP_KERNEL);
 
        iwl_pcie_rx_hw_init(trans, rxq);
 
@@ -731,7 +537,6 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
 
        /*if rxq->bd is NULL, it means that nothing has been allocated,
         * exit now */
@@ -740,15 +545,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
                return;
        }
 
-       cancel_work_sync(&rba->rx_alloc);
-       if (rba->alloc_wq) {
-               destroy_workqueue(rba->alloc_wq);
-               rba->alloc_wq = NULL;
-       }
-
-       spin_lock(&rba->lock);
-       iwl_pcie_rx_free_rba(trans);
-       spin_unlock(&rba->lock);
+       cancel_work_sync(&trans_pcie->rx_replenish);
 
        spin_lock(&rxq->lock);
        iwl_pcie_rxq_free_rbs(trans);
@@ -769,43 +566,6 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
        rxq->rb_stts = NULL;
 }
 
-/*
- * iwl_pcie_rx_reuse_rbd - Recycle used RBDs
- *
- * Called when a RBD can be reused. The RBD is transferred to the allocator.
- * When there are 2 empty RBDs - a request for allocation is posted
- */
-static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,
-                                 struct iwl_rx_mem_buffer *rxb,
-                                 struct iwl_rxq *rxq)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-
-       /* Count the used RBDs */
-       rxq->used_count++;
-
-       /* Move the RBD to the used list, will be moved to allocator in batches
-        * before claiming or posting a request*/
-       list_add_tail(&rxb->list, &rxq->rx_used);
-
-       /* If we have RX_POST_REQ_ALLOC new released rx buffers -
-        * issue a request for allocator. Modulo RX_CLAIM_REQ_ALLOC is
-        * used for the case we failed to claim RX_CLAIM_REQ_ALLOC,
-        * after but we still need to post another request.
-        */
-       if ((rxq->used_count % RX_CLAIM_REQ_ALLOC) == RX_POST_REQ_ALLOC) {
-               /* Move the 2 RBDs to the allocator ownership.
-                Allocator has another 6 from pool for the request completion*/
-               spin_lock(&rba->lock);
-               list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
-               spin_unlock(&rba->lock);
-
-               atomic_inc(&rba->req_pending);
-               queue_work(rba->alloc_wq, &rba->rx_alloc);
-       }
-}
-
 static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                                struct iwl_rx_mem_buffer *rxb)
 {
@@ -928,13 +688,13 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                         */
                        __free_pages(rxb->page, trans_pcie->rx_page_order);
                        rxb->page = NULL;
-                       iwl_pcie_rx_reuse_rbd(trans, rxb, rxq);
+                       list_add_tail(&rxb->list, &rxq->rx_used);
                } else {
                        list_add_tail(&rxb->list, &rxq->rx_free);
                        rxq->free_count++;
                }
        } else
-               iwl_pcie_rx_reuse_rbd(trans, rxb, rxq);
+               list_add_tail(&rxb->list, &rxq->rx_used);
 }
 
 /*
@@ -944,7 +704,10 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-       u32 r, i, j;
+       u32 r, i;
+       u8 fill_rx = 0;
+       u32 count = 8;
+       int total_empty;
 
 restart:
        spin_lock(&rxq->lock);
@@ -957,6 +720,14 @@ restart:
        if (i == r)
                IWL_DEBUG_RX(trans, "HW = SW = %d\n", r);
 
+       /* calculate total frames need to be restock after handling RX */
+       total_empty = r - rxq->write_actual;
+       if (total_empty < 0)
+               total_empty += RX_QUEUE_SIZE;
+
+       if (total_empty > (RX_QUEUE_SIZE / 2))
+               fill_rx = 1;
+
        while (i != r) {
                struct iwl_rx_mem_buffer *rxb;
 
@@ -968,48 +739,29 @@ restart:
                iwl_pcie_rx_handle_rb(trans, rxb);
 
                i = (i + 1) & RX_QUEUE_MASK;
-
-               /* If we have RX_CLAIM_REQ_ALLOC released rx buffers -
-                * try to claim the pre-allocated buffers from the allocator */
-               if (rxq->used_count >= RX_CLAIM_REQ_ALLOC) {
-                       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-                       struct iwl_rx_mem_buffer *out[RX_CLAIM_REQ_ALLOC];
-
-                       /* Add the remaining 6 empty RBDs for allocator use */
-                       spin_lock(&rba->lock);
-                       list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
-                       spin_unlock(&rba->lock);
-
-                       /* If not ready - continue, will try to reclaim later.
-                       * No need to reschedule work - allocator exits only on
-                       * success */
-                       if (!iwl_pcie_rx_allocator_get(trans, out)) {
-                               /* If success - then RX_CLAIM_REQ_ALLOC
-                                * buffers were retrieved and should be added
-                                * to free list */
-                               rxq->used_count -= RX_CLAIM_REQ_ALLOC;
-                               for (j = 0; j < RX_CLAIM_REQ_ALLOC; j++) {
-                                       list_add_tail(&out[j]->list,
-                                                     &rxq->rx_free);
-                                       rxq->free_count++;
-                               }
+               /* If there are a lot of unused frames,
+                * restock the Rx queue so ucode wont assert. */
+               if (fill_rx) {
+                       count++;
+                       if (count >= 8) {
+                               rxq->read = i;
+                               spin_unlock(&rxq->lock);
+                               iwl_pcie_rx_replenish(trans, GFP_ATOMIC);
+                               count = 0;
+                               goto restart;
                        }
                }
-               /* handle restock for two cases:
-               * - we just pulled buffers from the allocator
-               * - we have 8+ unstolen pages accumulated */
-               if (rxq->free_count >=  RX_CLAIM_REQ_ALLOC) {
-                       rxq->read = i;
-                       spin_unlock(&rxq->lock);
-                       iwl_pcie_rxq_restock(trans);
-                       goto restart;
-               }
        }
 
        /* Backtrack one entry */
        rxq->read = i;
        spin_unlock(&rxq->lock);
 
+       if (fill_rx)
+               iwl_pcie_rx_replenish(trans, GFP_ATOMIC);
+       else
+               iwl_pcie_rxq_restock(trans);
+
        if (trans_pcie->napi.poll)
                napi_gro_flush(&trans_pcie->napi, false);
 }
index 43ae658af6ec56506f9f0e8ed00022b890c3b9fb..9e144e71da0b5980264702a6210684cfa34edab5 100644 (file)
@@ -182,7 +182,7 @@ static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val)
 
 static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
 {
-       if (!trans->cfg->apmg_not_supported)
+       if (trans->cfg->apmg_not_supported)
                return;
 
        if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
@@ -478,10 +478,16 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
                if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000)
                        iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
                                          APMG_PCIDEV_STT_VAL_WAKE_ME);
-               else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+               else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
+                       iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+                                   CSR_RESET_LINK_PWR_MGMT_DISABLED);
                        iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
                                    CSR_HW_IF_CONFIG_REG_PREPARE |
                                    CSR_HW_IF_CONFIG_REG_ENABLE_PME);
+                       mdelay(1);
+                       iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+                                     CSR_RESET_LINK_PWR_MGMT_DISABLED);
+               }
                mdelay(5);
        }
 
@@ -575,6 +581,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
        if (ret >= 0)
                return 0;
 
+       iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+                   CSR_RESET_LINK_PWR_MGMT_DISABLED);
+       msleep(1);
+
        for (iter = 0; iter < 10; iter++) {
                /* If HW is not ready, prepare the conditions to check again */
                iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
@@ -582,8 +592,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
 
                do {
                        ret = iwl_pcie_set_hw_ready(trans);
-                       if (ret >= 0)
-                               return 0;
+                       if (ret >= 0) {
+                               ret = 0;
+                               goto out;
+                       }
 
                        usleep_range(200, 1000);
                        t += 200;
@@ -593,6 +605,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
 
        IWL_ERR(trans, "Couldn't prepare the card\n");
 
+out:
+       iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+                     CSR_RESET_LINK_PWR_MGMT_DISABLED);
+
        return ret;
 }
 
@@ -2459,7 +2475,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        struct iwl_trans_pcie *trans_pcie;
        struct iwl_trans *trans;
        u16 pci_cmd;
-       int err;
+       int ret;
 
        trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie),
                                &pdev->dev, cfg, &trans_ops_pcie, 0);
@@ -2474,8 +2490,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        spin_lock_init(&trans_pcie->ref_lock);
        init_waitqueue_head(&trans_pcie->ucode_write_waitq);
 
-       err = pci_enable_device(pdev);
-       if (err)
+       ret = pci_enable_device(pdev);
+       if (ret)
                goto out_no_pci;
 
        if (!cfg->base_params->pcie_l1_allowed) {
@@ -2491,23 +2507,23 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
 
        pci_set_master(pdev);
 
-       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
-       if (!err)
-               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
-       if (err) {
-               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-               if (!err)
-                       err = pci_set_consistent_dma_mask(pdev,
+       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
+       if (!ret)
+               ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
+       if (ret) {
+               ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (!ret)
+                       ret = pci_set_consistent_dma_mask(pdev,
                                                          DMA_BIT_MASK(32));
                /* both attempts failed: */
-               if (err) {
+               if (ret) {
                        dev_err(&pdev->dev, "No suitable DMA available\n");
                        goto out_pci_disable_device;
                }
        }
 
-       err = pci_request_regions(pdev, DRV_NAME);
-       if (err) {
+       ret = pci_request_regions(pdev, DRV_NAME);
+       if (ret) {
                dev_err(&pdev->dev, "pci_request_regions failed\n");
                goto out_pci_disable_device;
        }
@@ -2515,7 +2531,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);
        if (!trans_pcie->hw_base) {
                dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
-               err = -ENODEV;
+               ret = -ENODEV;
                goto out_pci_release_regions;
        }
 
@@ -2527,9 +2543,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        trans_pcie->pci_dev = pdev;
        iwl_disable_interrupts(trans);
 
-       err = pci_enable_msi(pdev);
-       if (err) {
-               dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", err);
+       ret = pci_enable_msi(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", ret);
                /* enable rfkill interrupt: hw bug w/a */
                pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
                if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
@@ -2547,11 +2563,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
         */
        if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
                unsigned long flags;
-               int ret;
 
                trans->hw_rev = (trans->hw_rev & 0xfff0) |
                                (CSR_HW_REV_STEP(trans->hw_rev << 2) << 2);
 
+               ret = iwl_pcie_prepare_card_hw(trans);
+               if (ret) {
+                       IWL_WARN(trans, "Exit HW not ready\n");
+                       goto out_pci_disable_msi;
+               }
+
                /*
                 * in-order to recognize C step driver should read chip version
                 * id located at the AUX bus MISC address space.
@@ -2591,13 +2612,14 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        /* Initialize the wait queue for commands */
        init_waitqueue_head(&trans_pcie->wait_command_queue);
 
-       if (iwl_pcie_alloc_ict(trans))
+       ret = iwl_pcie_alloc_ict(trans);
+       if (ret)
                goto out_pci_disable_msi;
 
-       err = request_threaded_irq(pdev->irq, iwl_pcie_isr,
+       ret = request_threaded_irq(pdev->irq, iwl_pcie_isr,
                                   iwl_pcie_irq_handler,
                                   IRQF_SHARED, DRV_NAME, trans);
-       if (err) {
+       if (ret) {
                IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
                goto out_free_ict;
        }
@@ -2617,5 +2639,5 @@ out_pci_disable_device:
        pci_disable_device(pdev);
 out_no_pci:
        iwl_trans_free(trans);
-       return ERR_PTR(err);
+       return ERR_PTR(ret);
 }
index 2b86c2135de36f627b397add88628bc47aa37271..607acb53c847558793d47a528d0830f9c79c8cbf 100644 (file)
@@ -1875,8 +1875,19 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
 
        /* start timer if queue currently empty */
        if (q->read_ptr == q->write_ptr) {
-               if (txq->wd_timeout)
-                       mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
+               if (txq->wd_timeout) {
+                       /*
+                        * If the TXQ is active, then set the timer, if not,
+                        * set the timer in remainder so that the timer will
+                        * be armed with the right value when the station will
+                        * wake up.
+                        */
+                       if (!txq->frozen)
+                               mod_timer(&txq->stuck_timer,
+                                         jiffies + txq->wd_timeout);
+                       else
+                               txq->frozen_expiry_remainder = txq->wd_timeout;
+               }
                IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id);
                iwl_trans_pcie_ref(trans);
        }
index b6cc9ff47fc2e59b3cc92fe4002f05e59d981e56..1c6788aecc62658fe2cc7c4961415ef4715c8dde 100644 (file)
@@ -172,6 +172,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
                (struct rsi_91x_sdiodev *)adapter->rsi_dev;
        u32 len;
        u32 num_blocks;
+       const u8 *fw;
        const struct firmware *fw_entry = NULL;
        u32 block_size = dev->tx_blk_size;
        int status = 0;
@@ -200,6 +201,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
                return status;
        }
 
+       /* Copy firmware into DMA-accessible memory */
+       fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+       if (!fw)
+               return -ENOMEM;
        len = fw_entry->size;
 
        if (len % 4)
@@ -210,7 +215,8 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
        rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len);
        rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
 
-       status = rsi_copy_to_card(common, fw_entry->data, len, num_blocks);
+       status = rsi_copy_to_card(common, fw, len, num_blocks);
+       kfree(fw);
        release_firmware(fw_entry);
        return status;
 }
index 1106ce76707e1095fd523c5c541fa3740e9c9496..30c2cf7fa93b0c6015d22236c3a9189b462cb064 100644 (file)
@@ -146,7 +146,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
                return status;
        }
 
+       /* Copy firmware into DMA-accessible memory */
        fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+       if (!fw)
+               return -ENOMEM;
        len = fw_entry->size;
 
        if (len % 4)
@@ -158,6 +161,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
        rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
 
        status = rsi_copy_to_card(common, fw, len, num_blocks);
+       kfree(fw);
        release_firmware(fw_entry);
        return status;
 }
index 3b3a88b53b119909112a806ee71ab4d4bfa67a79..585d0883c7e58760eed503de64ced513c8331c82 100644 (file)
@@ -1015,9 +1015,12 @@ static void send_beacon_frame(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
+       struct rtl_tcb_desc tcb_desc;
 
-       if (skb)
-               rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, NULL);
+       if (skb) {
+               memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+               rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc);
+       }
 }
 
 static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
index 1017f02d7bf7520868b25330493822e08f7826a0..7bf88d9dcdc3fc4732170c121ef78d5a85ca3fa9 100644 (file)
@@ -385,6 +385,7 @@ module_param_named(debug, rtl8723be_mod_params.debug, int, 0444);
 module_param_named(ips, rtl8723be_mod_params.inactiveps, bool, 0444);
 module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444);
 module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444);
+module_param_named(msi, rtl8723be_mod_params.msi_support, bool, 0444);
 module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog,
                   bool, 0444);
 MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
index 1a83e190fc15e4158b5e441cc267ad149d465abe..28577a31549d1569032d63457464fe11fdf44d32 100644 (file)
@@ -61,6 +61,12 @@ void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue,
 void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue)
 {
        atomic_dec(&queue->inflight_packets);
+
+       /* Wake the dealloc thread _after_ decrementing inflight_packets so
+        * that if kthread_stop() has already been called, the dealloc thread
+        * does not wait forever with nothing to wake it.
+        */
+       wake_up(&queue->dealloc_wq);
 }
 
 int xenvif_schedulable(struct xenvif *vif)
index 880d0d63e872e5725d76fe998db0282c749f45d6..3f44b522b8311a2c64eba48e6a9b7217ea0cb3a7 100644 (file)
@@ -810,23 +810,17 @@ static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
 static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *queue,
                                                        struct sk_buff *skb,
                                                        struct xen_netif_tx_request *txp,
-                                                       struct gnttab_map_grant_ref *gop)
+                                                       struct gnttab_map_grant_ref *gop,
+                                                       unsigned int frag_overflow,
+                                                       struct sk_buff *nskb)
 {
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        skb_frag_t *frags = shinfo->frags;
        u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
        int start;
        pending_ring_idx_t index;
-       unsigned int nr_slots, frag_overflow = 0;
+       unsigned int nr_slots;
 
-       /* At this point shinfo->nr_frags is in fact the number of
-        * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
-        */
-       if (shinfo->nr_frags > MAX_SKB_FRAGS) {
-               frag_overflow = shinfo->nr_frags - MAX_SKB_FRAGS;
-               BUG_ON(frag_overflow > MAX_SKB_FRAGS);
-               shinfo->nr_frags = MAX_SKB_FRAGS;
-       }
        nr_slots = shinfo->nr_frags;
 
        /* Skip first skb fragment if it is on same page as header fragment. */
@@ -841,13 +835,6 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *que
        }
 
        if (frag_overflow) {
-               struct sk_buff *nskb = xenvif_alloc_skb(0);
-               if (unlikely(nskb == NULL)) {
-                       if (net_ratelimit())
-                               netdev_err(queue->vif->dev,
-                                          "Can't allocate the frag_list skb.\n");
-                       return NULL;
-               }
 
                shinfo = skb_shinfo(nskb);
                frags = shinfo->frags;
@@ -1175,9 +1162,10 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                                     unsigned *copy_ops,
                                     unsigned *map_ops)
 {
-       struct gnttab_map_grant_ref *gop = queue->tx_map_ops, *request_gop;
-       struct sk_buff *skb;
+       struct gnttab_map_grant_ref *gop = queue->tx_map_ops;
+       struct sk_buff *skb, *nskb;
        int ret;
+       unsigned int frag_overflow;
 
        while (skb_queue_len(&queue->tx_queue) < budget) {
                struct xen_netif_tx_request txreq;
@@ -1265,6 +1253,29 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                        break;
                }
 
+               skb_shinfo(skb)->nr_frags = ret;
+               if (data_len < txreq.size)
+                       skb_shinfo(skb)->nr_frags++;
+               /* At this point shinfo->nr_frags is in fact the number of
+                * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
+                */
+               frag_overflow = 0;
+               nskb = NULL;
+               if (skb_shinfo(skb)->nr_frags > MAX_SKB_FRAGS) {
+                       frag_overflow = skb_shinfo(skb)->nr_frags - MAX_SKB_FRAGS;
+                       BUG_ON(frag_overflow > MAX_SKB_FRAGS);
+                       skb_shinfo(skb)->nr_frags = MAX_SKB_FRAGS;
+                       nskb = xenvif_alloc_skb(0);
+                       if (unlikely(nskb == NULL)) {
+                               kfree_skb(skb);
+                               xenvif_tx_err(queue, &txreq, idx);
+                               if (net_ratelimit())
+                                       netdev_err(queue->vif->dev,
+                                                  "Can't allocate the frag_list skb.\n");
+                               break;
+                       }
+               }
+
                if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
                        struct xen_netif_extra_info *gso;
                        gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
@@ -1272,6 +1283,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                        if (xenvif_set_skb_gso(queue->vif, skb, gso)) {
                                /* Failure in xenvif_set_skb_gso is fatal. */
                                kfree_skb(skb);
+                               kfree_skb(nskb);
                                break;
                        }
                }
@@ -1294,9 +1306,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
 
                (*copy_ops)++;
 
-               skb_shinfo(skb)->nr_frags = ret;
                if (data_len < txreq.size) {
-                       skb_shinfo(skb)->nr_frags++;
                        frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
                                             pending_idx);
                        xenvif_tx_create_map_op(queue, pending_idx, &txreq, gop);
@@ -1310,13 +1320,8 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
 
                queue->pending_cons++;
 
-               request_gop = xenvif_get_requests(queue, skb, txfrags, gop);
-               if (request_gop == NULL) {
-                       kfree_skb(skb);
-                       xenvif_tx_err(queue, &txreq, idx);
-                       break;
-               }
-               gop = request_gop;
+               gop = xenvif_get_requests(queue, skb, txfrags, gop,
+                                         frag_overflow, nskb);
 
                __skb_queue_tail(&queue->tx_queue, skb);
 
@@ -1536,7 +1541,6 @@ void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success)
                smp_wmb();
                queue->dealloc_prod++;
        } while (ubuf);
-       wake_up(&queue->dealloc_wq);
        spin_unlock_irqrestore(&queue->callback_lock, flags);
 
        if (likely(zerocopy_success))
@@ -1566,13 +1570,13 @@ static inline void xenvif_tx_dealloc_action(struct xenvif_queue *queue)
                smp_rmb();
 
                while (dc != dp) {
-                       BUG_ON(gop - queue->tx_unmap_ops > MAX_PENDING_REQS);
+                       BUG_ON(gop - queue->tx_unmap_ops >= MAX_PENDING_REQS);
                        pending_idx =
                                queue->dealloc_ring[pending_index(dc++)];
 
-                       pending_idx_release[gop-queue->tx_unmap_ops] =
+                       pending_idx_release[gop - queue->tx_unmap_ops] =
                                pending_idx;
-                       queue->pages_to_unmap[gop-queue->tx_unmap_ops] =
+                       queue->pages_to_unmap[gop - queue->tx_unmap_ops] =
                                queue->mmap_pages[pending_idx];
                        gnttab_set_unmap_op(gop,
                                            idx_to_kaddr(queue, pending_idx),
index 23435f2a5486f806ee8f686fdb898d0815a68013..2e2530743831a19f2ca4db3b313d1f8b2db44ebb 100644 (file)
@@ -114,7 +114,7 @@ int ntb_register_device(struct ntb_dev *ntb)
        ntb->dev.bus = &ntb_bus;
        ntb->dev.parent = &ntb->pdev->dev;
        ntb->dev.release = ntb_dev_release;
-       dev_set_name(&ntb->dev, pci_name(ntb->pdev));
+       dev_set_name(&ntb->dev, "%s", pci_name(ntb->pdev));
 
        ntb->ctx = NULL;
        ntb->ctx_ops = NULL;
index efe3ad4122f2ee1094da78c1bb31d86642b5b3a6..1c6386d5f79c742737e4ee1a8a2b99df686ffaa0 100644 (file)
@@ -142,10 +142,11 @@ struct ntb_transport_qp {
 
        void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
                           void *data, int len);
+       struct list_head rx_post_q;
        struct list_head rx_pend_q;
        struct list_head rx_free_q;
-       spinlock_t ntb_rx_pend_q_lock;
-       spinlock_t ntb_rx_free_q_lock;
+       /* ntb_rx_q_lock: synchronize access to rx_XXXX_q */
+       spinlock_t ntb_rx_q_lock;
        void *rx_buff;
        unsigned int rx_index;
        unsigned int rx_max_entry;
@@ -211,6 +212,8 @@ struct ntb_transport_ctx {
        bool link_is_up;
        struct delayed_work link_work;
        struct work_struct link_cleanup;
+
+       struct dentry *debugfs_node_dir;
 };
 
 enum {
@@ -436,13 +439,17 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
        char *buf;
        ssize_t ret, out_offset, out_count;
 
+       qp = filp->private_data;
+
+       if (!qp || !qp->link_is_up)
+               return 0;
+
        out_count = 1000;
 
        buf = kmalloc(out_count, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
-       qp = filp->private_data;
        out_offset = 0;
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "NTB QP stats\n");
@@ -534,6 +541,27 @@ out:
        return entry;
 }
 
+static struct ntb_queue_entry *ntb_list_mv(spinlock_t *lock,
+                                          struct list_head *list,
+                                          struct list_head *to_list)
+{
+       struct ntb_queue_entry *entry;
+       unsigned long flags;
+
+       spin_lock_irqsave(lock, flags);
+
+       if (list_empty(list)) {
+               entry = NULL;
+       } else {
+               entry = list_first_entry(list, struct ntb_queue_entry, entry);
+               list_move_tail(&entry->entry, to_list);
+       }
+
+       spin_unlock_irqrestore(lock, flags);
+
+       return entry;
+}
+
 static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt,
                                     unsigned int qp_num)
 {
@@ -601,13 +629,16 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
 }
 
 static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
-                     unsigned int size)
+                     resource_size_t size)
 {
        struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
        struct pci_dev *pdev = nt->ndev->pdev;
-       unsigned int xlat_size, buff_size;
+       size_t xlat_size, buff_size;
        int rc;
 
+       if (!size)
+               return -EINVAL;
+
        xlat_size = round_up(size, mw->xlat_align_size);
        buff_size = round_up(size, mw->xlat_align);
 
@@ -627,7 +658,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
        if (!mw->virt_addr) {
                mw->xlat_size = 0;
                mw->buff_size = 0;
-               dev_err(&pdev->dev, "Unable to alloc MW buff of size %d\n",
+               dev_err(&pdev->dev, "Unable to alloc MW buff of size %zu\n",
                        buff_size);
                return -ENOMEM;
        }
@@ -867,6 +898,8 @@ static void ntb_qp_link_work(struct work_struct *work)
 
                if (qp->event_handler)
                        qp->event_handler(qp->cb_data, qp->link_is_up);
+
+               tasklet_schedule(&qp->rxc_db_work);
        } else if (nt->link_is_up)
                schedule_delayed_work(&qp->link_work,
                                      msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
@@ -923,12 +956,12 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
        qp->tx_max_frame = min(transport_mtu, tx_size / 2);
        qp->tx_max_entry = tx_size / qp->tx_max_frame;
 
-       if (nt_debugfs_dir) {
+       if (nt->debugfs_node_dir) {
                char debugfs_name[4];
 
                snprintf(debugfs_name, 4, "qp%d", qp_num);
                qp->debugfs_dir = debugfs_create_dir(debugfs_name,
-                                                    nt_debugfs_dir);
+                                                    nt->debugfs_node_dir);
 
                qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR,
                                                        qp->debugfs_dir, qp,
@@ -941,10 +974,10 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
        INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work);
        INIT_WORK(&qp->link_cleanup, ntb_qp_link_cleanup_work);
 
-       spin_lock_init(&qp->ntb_rx_pend_q_lock);
-       spin_lock_init(&qp->ntb_rx_free_q_lock);
+       spin_lock_init(&qp->ntb_rx_q_lock);
        spin_lock_init(&qp->ntb_tx_free_q_lock);
 
+       INIT_LIST_HEAD(&qp->rx_post_q);
        INIT_LIST_HEAD(&qp->rx_pend_q);
        INIT_LIST_HEAD(&qp->rx_free_q);
        INIT_LIST_HEAD(&qp->tx_free_q);
@@ -1031,6 +1064,12 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
                goto err2;
        }
 
+       if (nt_debugfs_dir) {
+               nt->debugfs_node_dir =
+                       debugfs_create_dir(pci_name(ndev->pdev),
+                                          nt_debugfs_dir);
+       }
+
        for (i = 0; i < qp_count; i++) {
                rc = ntb_transport_init_queue(nt, i);
                if (rc)
@@ -1107,22 +1146,47 @@ static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev)
        kfree(nt);
 }
 
-static void ntb_rx_copy_callback(void *data)
+static void ntb_complete_rxc(struct ntb_transport_qp *qp)
 {
-       struct ntb_queue_entry *entry = data;
-       struct ntb_transport_qp *qp = entry->qp;
-       void *cb_data = entry->cb_data;
-       unsigned int len = entry->len;
-       struct ntb_payload_header *hdr = entry->rx_hdr;
+       struct ntb_queue_entry *entry;
+       void *cb_data;
+       unsigned int len;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&qp->ntb_rx_q_lock, irqflags);
+
+       while (!list_empty(&qp->rx_post_q)) {
+               entry = list_first_entry(&qp->rx_post_q,
+                                        struct ntb_queue_entry, entry);
+               if (!(entry->flags & DESC_DONE_FLAG))
+                       break;
+
+               entry->rx_hdr->flags = 0;
+               iowrite32(entry->index, &qp->rx_info->entry);
 
-       hdr->flags = 0;
+               cb_data = entry->cb_data;
+               len = entry->len;
 
-       iowrite32(entry->index, &qp->rx_info->entry);
+               list_move_tail(&entry->entry, &qp->rx_free_q);
 
-       ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q);
+               spin_unlock_irqrestore(&qp->ntb_rx_q_lock, irqflags);
 
-       if (qp->rx_handler && qp->client_ready)
-               qp->rx_handler(qp, qp->cb_data, cb_data, len);
+               if (qp->rx_handler && qp->client_ready)
+                       qp->rx_handler(qp, qp->cb_data, cb_data, len);
+
+               spin_lock_irqsave(&qp->ntb_rx_q_lock, irqflags);
+       }
+
+       spin_unlock_irqrestore(&qp->ntb_rx_q_lock, irqflags);
+}
+
+static void ntb_rx_copy_callback(void *data)
+{
+       struct ntb_queue_entry *entry = data;
+
+       entry->flags |= DESC_DONE_FLAG;
+
+       ntb_complete_rxc(entry->qp);
 }
 
 static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset)
@@ -1138,19 +1202,18 @@ static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset)
        ntb_rx_copy_callback(entry);
 }
 
-static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset,
-                        size_t len)
+static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
 {
        struct dma_async_tx_descriptor *txd;
        struct ntb_transport_qp *qp = entry->qp;
        struct dma_chan *chan = qp->dma_chan;
        struct dma_device *device;
-       size_t pay_off, buff_off;
+       size_t pay_off, buff_off, len;
        struct dmaengine_unmap_data *unmap;
        dma_cookie_t cookie;
        void *buf = entry->buf;
 
-       entry->len = len;
+       len = entry->len;
 
        if (!chan)
                goto err;
@@ -1226,7 +1289,6 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
        struct ntb_payload_header *hdr;
        struct ntb_queue_entry *entry;
        void *offset;
-       int rc;
 
        offset = qp->rx_buff + qp->rx_max_frame * qp->rx_index;
        hdr = offset + qp->rx_max_frame - sizeof(struct ntb_payload_header);
@@ -1255,65 +1317,43 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
                return -EIO;
        }
 
-       entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
+       entry = ntb_list_mv(&qp->ntb_rx_q_lock, &qp->rx_pend_q, &qp->rx_post_q);
        if (!entry) {
                dev_dbg(&qp->ndev->pdev->dev, "no receive buffer\n");
                qp->rx_err_no_buf++;
-
-               rc = -ENOMEM;
-               goto err;
+               return -EAGAIN;
        }
 
+       entry->rx_hdr = hdr;
+       entry->index = qp->rx_index;
+
        if (hdr->len > entry->len) {
                dev_dbg(&qp->ndev->pdev->dev,
                        "receive buffer overflow! Wanted %d got %d\n",
                        hdr->len, entry->len);
                qp->rx_err_oflow++;
 
-               rc = -EIO;
-               goto err;
-       }
+               entry->len = -EIO;
+               entry->flags |= DESC_DONE_FLAG;
 
-       dev_dbg(&qp->ndev->pdev->dev,
-               "RX OK index %u ver %u size %d into buf size %d\n",
-               qp->rx_index, hdr->ver, hdr->len, entry->len);
+               ntb_complete_rxc(qp);
+       } else {
+               dev_dbg(&qp->ndev->pdev->dev,
+                       "RX OK index %u ver %u size %d into buf size %d\n",
+                       qp->rx_index, hdr->ver, hdr->len, entry->len);
 
-       qp->rx_bytes += hdr->len;
-       qp->rx_pkts++;
+               qp->rx_bytes += hdr->len;
+               qp->rx_pkts++;
 
-       entry->index = qp->rx_index;
-       entry->rx_hdr = hdr;
+               entry->len = hdr->len;
 
-       ntb_async_rx(entry, offset, hdr->len);
+               ntb_async_rx(entry, offset);
+       }
 
        qp->rx_index++;
        qp->rx_index %= qp->rx_max_entry;
 
        return 0;
-
-err:
-       /* FIXME: if this syncrhonous update of the rx_index gets ahead of
-        * asyncrhonous ntb_rx_copy_callback of previous entry, there are three
-        * scenarios:
-        *
-        * 1) The peer might miss this update, but observe the update
-        * from the memcpy completion callback.  In this case, the buffer will
-        * not be freed on the peer to be reused for a different packet.  The
-        * successful rx of a later packet would clear the condition, but the
-        * condition could persist if several rx fail in a row.
-        *
-        * 2) The peer may observe this update before the asyncrhonous copy of
-        * prior packets is completed.  The peer may overwrite the buffers of
-        * the prior packets before they are copied.
-        *
-        * 3) Both: the peer may observe the update, and then observe the index
-        * decrement by the asynchronous completion callback.  Who knows what
-        * badness that will cause.
-        */
-       hdr->flags = 0;
-       iowrite32(qp->rx_index, &qp->rx_info->entry);
-
-       return rc;
 }
 
 static void ntb_transport_rxc_db(unsigned long data)
@@ -1333,7 +1373,7 @@ static void ntb_transport_rxc_db(unsigned long data)
                        break;
        }
 
-       if (qp->dma_chan)
+       if (i && qp->dma_chan)
                dma_async_issue_pending(qp->dma_chan);
 
        if (i == qp->rx_max_entry) {
@@ -1609,7 +1649,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
                        goto err1;
 
                entry->qp = qp;
-               ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry,
+               ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry,
                             &qp->rx_free_q);
        }
 
@@ -1634,7 +1674,7 @@ err2:
        while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
                kfree(entry);
 err1:
-       while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
+       while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q)))
                kfree(entry);
        if (qp->dma_chan)
                dma_release_channel(qp->dma_chan);
@@ -1652,7 +1692,6 @@ EXPORT_SYMBOL_GPL(ntb_transport_create_queue);
  */
 void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 {
-       struct ntb_transport_ctx *nt = qp->transport;
        struct pci_dev *pdev;
        struct ntb_queue_entry *entry;
        u64 qp_bit;
@@ -1689,18 +1728,23 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
        qp->tx_handler = NULL;
        qp->event_handler = NULL;
 
-       while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
+       while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q)))
                kfree(entry);
 
-       while ((entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q))) {
-               dev_warn(&pdev->dev, "Freeing item from a non-empty queue\n");
+       while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_pend_q))) {
+               dev_warn(&pdev->dev, "Freeing item from non-empty rx_pend_q\n");
+               kfree(entry);
+       }
+
+       while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_post_q))) {
+               dev_warn(&pdev->dev, "Freeing item from non-empty rx_post_q\n");
                kfree(entry);
        }
 
        while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
                kfree(entry);
 
-       nt->qp_bitmap_free |= qp_bit;
+       qp->transport->qp_bitmap_free |= qp_bit;
 
        dev_info(&pdev->dev, "NTB Transport QP %d freed\n", qp->qp_num);
 }
@@ -1724,14 +1768,14 @@ void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len)
        if (!qp || qp->client_ready)
                return NULL;
 
-       entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
+       entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_pend_q);
        if (!entry)
                return NULL;
 
        buf = entry->cb_data;
        *len = entry->len;
 
-       ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q);
+       ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_free_q);
 
        return buf;
 }
@@ -1757,15 +1801,18 @@ int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
        if (!qp)
                return -EINVAL;
 
-       entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q);
+       entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q);
        if (!entry)
                return -ENOMEM;
 
        entry->cb_data = cb;
        entry->buf = data;
        entry->len = len;
+       entry->flags = 0;
+
+       ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_pend_q);
 
-       ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, &qp->rx_pend_q);
+       tasklet_schedule(&qp->rxc_db_work);
 
        return 0;
 }
index a5233422f9dc5f770b98d0555560fb87a5f83ff0..7384455792bfb629ed6a2b9a5dbe40d1f58f2627 100644 (file)
@@ -458,10 +458,15 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus,
                nvdimm_bus_unlock(dev);
        }
        if (is_nd_btt(dev) && probe) {
+               struct nd_btt *nd_btt = to_nd_btt(dev);
+
                nd_region = to_nd_region(dev->parent);
                nvdimm_bus_lock(dev);
                if (nd_region->btt_seed == dev)
                        nd_region_create_btt_seed(nd_region);
+               if (nd_region->ns_seed == &nd_btt->ndns->dev &&
+                               is_nd_blk(dev->parent))
+                       nd_region_create_blk_seed(nd_region);
                nvdimm_bus_unlock(dev);
        }
 }
index 8df1b1777745e8e0dfb46611197a8238c929af4e..59bb8556e43ac8f975485465ca8d1b0fdfeba3c5 100644 (file)
@@ -47,7 +47,7 @@ config OF_DYNAMIC
 
 config OF_ADDRESS
        def_bool y
-       depends on !SPARC
+       depends on !SPARC && HAS_IOMEM
        select OF_ADDRESS_PCI if PCI
 
 config OF_ADDRESS_PCI
index 18016341d5a91656b29220b414faddae48188648..9f71770b6226f9ed3d4ceab7bb95ea3f4ba55b6c 100644 (file)
@@ -979,7 +979,6 @@ static struct platform_driver unittest_driver = {
        .remove                 = unittest_remove,
        .driver = {
                .name           = "unittest",
-               .owner          = THIS_MODULE,
                .of_match_table = of_match_ptr(unittest_match),
        },
 };
@@ -1666,7 +1665,6 @@ static const struct i2c_device_id unittest_i2c_dev_id[] = {
 static struct i2c_driver unittest_i2c_dev_driver = {
        .driver = {
                .name = "unittest-i2c-dev",
-               .owner = THIS_MODULE,
        },
        .probe = unittest_i2c_dev_probe,
        .remove = unittest_i2c_dev_remove,
@@ -1761,7 +1759,6 @@ static const struct i2c_device_id unittest_i2c_mux_id[] = {
 static struct i2c_driver unittest_i2c_mux_driver = {
        .driver = {
                .name = "unittest-i2c-mux",
-               .owner = THIS_MODULE,
        },
        .probe = unittest_i2c_mux_probe,
        .remove = unittest_i2c_mux_remove,
index 8067f54ce050a6c8cf3a4c18d9b4ea560f017d94..5ce5ef211bdbdf575752e150edc6e26cc683e82d 100644 (file)
@@ -891,8 +891,10 @@ parport_register_dev_model(struct parport *port, const char *name,
        par_dev->dev.release = free_pardevice;
        par_dev->devmodel = true;
        ret = device_register(&par_dev->dev);
-       if (ret)
-               goto err_put_dev;
+       if (ret) {
+               put_device(&par_dev->dev);
+               goto err_put_port;
+       }
 
        /* Chain this onto the list */
        par_dev->prev = NULL;
@@ -907,7 +909,8 @@ parport_register_dev_model(struct parport *port, const char *name,
                        spin_unlock(&port->physport->pardevice_lock);
                        pr_debug("%s: cannot grant exclusive access for device %s\n",
                                 port->name, name);
-                       goto err_put_dev;
+                       device_unregister(&par_dev->dev);
+                       goto err_put_port;
                }
                port->flags |= PARPORT_FLAG_EXCL;
        }
@@ -938,8 +941,6 @@ parport_register_dev_model(struct parport *port, const char *name,
 
        return par_dev;
 
-err_put_dev:
-       put_device(&par_dev->dev);
 err_free_devname:
        kfree(devname);
 err_free_par_dev:
index c0e6ede3e27d7cd07d92c247af58367e1b6d85a1..6b8dd162f644214ba24fd666b5aa6c94467d964d 100644 (file)
@@ -56,6 +56,7 @@ config PHY_EXYNOS_MIPI_VIDEO
 
 config PHY_PXA_28NM_HSIC
        tristate "Marvell USB HSIC 28nm PHY Driver"
+       depends on HAS_IOMEM
        select GENERIC_PHY
        help
          Enable this to support Marvell USB HSIC PHY driver for Marvell
@@ -66,6 +67,7 @@ config PHY_PXA_28NM_HSIC
 
 config PHY_PXA_28NM_USB2
        tristate "Marvell USB 2.0 28nm PHY Driver"
+       depends on HAS_IOMEM
        select GENERIC_PHY
        help
          Enable this to support Marvell USB 2.0 PHY driver for Marvell
index c6fc95b530835569b040f193f6cf051f7198f7b9..335e06d66ed9a5100cbdda511e6c206238651814 100644 (file)
 
 static const u32 phy_berlin_pll_dividers[] = {
        /* Berlin 2 */
-       CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
-       /* Berlin 2CD */
        CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55),
+       /* Berlin 2CD/Q */
+       CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
 };
 
 struct phy_berlin_usb_priv {
index e17c539e4f6fbb138c04957532f3a329a8556b4a..2dad7e820ff0b16b7447b708f0c147b2e0289f02 100644 (file)
@@ -212,6 +212,7 @@ void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled)
 
        sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
 }
+EXPORT_SYMBOL_GPL(sun4i_usb_phy_set_squelch_detect);
 
 static struct phy_ops sun4i_usb_phy_ops = {
        .init           = sun4i_usb_phy_init,
index 53f295c1bab1a72108d84b955714b8aef4d7e951..08020dc2c7c8c3496987589841fc0ddb0b1c9ff7 100644 (file)
@@ -28,7 +28,8 @@
 #include <linux/delay.h>
 #include <linux/phy/omap_control_phy.h>
 #include <linux/of_platform.h>
-#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #define        PLL_STATUS              0x00000004
 #define        PLL_GO                  0x00000008
@@ -53,6 +54,8 @@
 #define        PLL_LOCK                0x2
 #define        PLL_IDLE                0x1
 
+#define SATA_PLL_SOFT_RESET    BIT(18)
+
 /*
  * This is an Empirical value that works, need to confirm the actual
  * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
@@ -83,10 +86,9 @@ struct ti_pipe3 {
        struct clk              *refclk;
        struct clk              *div_clk;
        struct pipe3_dpll_map   *dpll_map;
-       bool                    enabled;
-       spinlock_t              lock;   /* serialize clock enable/disable */
-       /* the below flag is needed specifically for SATA */
-       bool                    refclk_enabled;
+       struct regmap           *dpll_reset_syscon; /* ctrl. reg. acces */
+       unsigned int            dpll_reset_reg; /* reg. index within syscon */
+       bool                    sata_refclk_enabled;
 };
 
 static struct pipe3_dpll_map dpll_map_usb[] = {
@@ -137,6 +139,9 @@ static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(struct ti_pipe3 *phy)
        return NULL;
 }
 
+static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy);
+static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy);
+
 static int ti_pipe3_power_off(struct phy *x)
 {
        struct ti_pipe3 *phy = phy_get_drvdata(x);
@@ -217,6 +222,7 @@ static int ti_pipe3_init(struct phy *x)
        u32 val;
        int ret = 0;
 
+       ti_pipe3_enable_clocks(phy);
        /*
         * Set pcie_pcs register to 0x96 for proper functioning of phy
         * as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table
@@ -250,33 +256,46 @@ static int ti_pipe3_exit(struct phy *x)
        u32 val;
        unsigned long timeout;
 
-       /* SATA DPLL can't be powered down due to Errata i783 and PCIe
-        * does not have internal DPLL
+       /* If dpll_reset_syscon is not present we wont power down SATA DPLL
+        * due to Errata i783
         */
-       if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") ||
-           of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie"))
+       if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") &&
+           !phy->dpll_reset_syscon)
                return 0;
 
-       /* Put DPLL in IDLE mode */
-       val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
-       val |= PLL_IDLE;
-       ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+       /* PCIe doesn't have internal DPLL */
+       if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) {
+               /* Put DPLL in IDLE mode */
+               val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+               val |= PLL_IDLE;
+               ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
 
-       /* wait for LDO and Oscillator to power down */
-       timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME);
-       do {
-               cpu_relax();
-               val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
-               if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
-                       break;
-       } while (!time_after(jiffies, timeout));
+               /* wait for LDO and Oscillator to power down */
+               timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME);
+               do {
+                       cpu_relax();
+                       val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+                       if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
+                               break;
+               } while (!time_after(jiffies, timeout));
+
+               if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
+                       dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n",
+                               val);
+                       return -EBUSY;
+               }
+       }
 
-       if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
-               dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n",
-                       val);
-               return -EBUSY;
+       /* i783: SATA needs control bit toggle after PLL unlock */
+       if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) {
+               regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
+                                  SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET);
+               regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
+                                  SATA_PLL_SOFT_RESET, 0);
        }
 
+       ti_pipe3_disable_clocks(phy);
+
        return 0;
 }
 static struct phy_ops ops = {
@@ -306,7 +325,6 @@ static int ti_pipe3_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        phy->dev                = &pdev->dev;
-       spin_lock_init(&phy->lock);
 
        if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
                match = of_match_device(ti_pipe3_id_table, &pdev->dev);
@@ -350,6 +368,21 @@ static int ti_pipe3_probe(struct platform_device *pdev)
                }
        } else {
                phy->wkupclk = ERR_PTR(-ENODEV);
+               phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node,
+                                                       "syscon-pllreset");
+               if (IS_ERR(phy->dpll_reset_syscon)) {
+                       dev_info(&pdev->dev,
+                                "can't get syscon-pllreset, sata dpll won't idle\n");
+                       phy->dpll_reset_syscon = NULL;
+               } else {
+                       if (of_property_read_u32_index(node,
+                                                      "syscon-pllreset", 1,
+                                                      &phy->dpll_reset_reg)) {
+                               dev_err(&pdev->dev,
+                                       "couldn't get pllreset reg. offset\n");
+                               return -EINVAL;
+                       }
+               }
        }
 
        if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
@@ -403,6 +436,16 @@ static int ti_pipe3_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, phy);
        pm_runtime_enable(phy->dev);
 
+       /*
+        * Prevent auto-disable of refclk for SATA PHY due to Errata i783
+        */
+       if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
+               if (!IS_ERR(phy->refclk)) {
+                       clk_prepare_enable(phy->refclk);
+                       phy->sata_refclk_enabled = true;
+               }
+       }
+
        generic_phy = devm_phy_create(phy->dev, NULL, &ops);
        if (IS_ERR(generic_phy))
                return PTR_ERR(generic_phy);
@@ -413,63 +456,33 @@ static int ti_pipe3_probe(struct platform_device *pdev)
        if (IS_ERR(phy_provider))
                return PTR_ERR(phy_provider);
 
-       pm_runtime_get(&pdev->dev);
-
        return 0;
 }
 
 static int ti_pipe3_remove(struct platform_device *pdev)
 {
-       if (!pm_runtime_suspended(&pdev->dev))
-               pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int ti_pipe3_enable_refclk(struct ti_pipe3 *phy)
+static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
 {
-       if (!IS_ERR(phy->refclk) && !phy->refclk_enabled) {
-               int ret;
+       int ret = 0;
 
+       if (!IS_ERR(phy->refclk)) {
                ret = clk_prepare_enable(phy->refclk);
                if (ret) {
                        dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
                        return ret;
                }
-               phy->refclk_enabled = true;
        }
 
-       return 0;
-}
-
-static void ti_pipe3_disable_refclk(struct ti_pipe3 *phy)
-{
-       if (!IS_ERR(phy->refclk))
-               clk_disable_unprepare(phy->refclk);
-
-       phy->refclk_enabled = false;
-}
-
-static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
-{
-       int ret = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&phy->lock, flags);
-       if (phy->enabled)
-               goto err1;
-
-       ret = ti_pipe3_enable_refclk(phy);
-       if (ret)
-               goto err1;
-
        if (!IS_ERR(phy->wkupclk)) {
                ret = clk_prepare_enable(phy->wkupclk);
                if (ret) {
                        dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
-                       goto err2;
+                       goto disable_refclk;
                }
        }
 
@@ -477,96 +490,43 @@ static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
                ret = clk_prepare_enable(phy->div_clk);
                if (ret) {
                        dev_err(phy->dev, "Failed to enable div_clk %d\n", ret);
-                       goto err3;
+                       goto disable_wkupclk;
                }
        }
 
-       phy->enabled = true;
-       spin_unlock_irqrestore(&phy->lock, flags);
        return 0;
 
-err3:
+disable_wkupclk:
        if (!IS_ERR(phy->wkupclk))
                clk_disable_unprepare(phy->wkupclk);
 
-err2:
+disable_refclk:
        if (!IS_ERR(phy->refclk))
                clk_disable_unprepare(phy->refclk);
 
-       ti_pipe3_disable_refclk(phy);
-err1:
-       spin_unlock_irqrestore(&phy->lock, flags);
        return ret;
 }
 
 static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&phy->lock, flags);
-       if (!phy->enabled) {
-               spin_unlock_irqrestore(&phy->lock, flags);
-               return;
-       }
-
        if (!IS_ERR(phy->wkupclk))
                clk_disable_unprepare(phy->wkupclk);
-       /* Don't disable refclk for SATA PHY due to Errata i783 */
-       if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
-               ti_pipe3_disable_refclk(phy);
+       if (!IS_ERR(phy->refclk)) {
+               clk_disable_unprepare(phy->refclk);
+               /*
+                * SATA refclk needs an additional disable as we left it
+                * on in probe to avoid Errata i783
+                */
+               if (phy->sata_refclk_enabled) {
+                       clk_disable_unprepare(phy->refclk);
+                       phy->sata_refclk_enabled = false;
+               }
+       }
+
        if (!IS_ERR(phy->div_clk))
                clk_disable_unprepare(phy->div_clk);
-       phy->enabled = false;
-       spin_unlock_irqrestore(&phy->lock, flags);
 }
 
-static int ti_pipe3_runtime_suspend(struct device *dev)
-{
-       struct ti_pipe3 *phy = dev_get_drvdata(dev);
-
-       ti_pipe3_disable_clocks(phy);
-       return 0;
-}
-
-static int ti_pipe3_runtime_resume(struct device *dev)
-{
-       struct ti_pipe3 *phy = dev_get_drvdata(dev);
-       int ret = 0;
-
-       ret = ti_pipe3_enable_clocks(phy);
-       return ret;
-}
-
-static int ti_pipe3_suspend(struct device *dev)
-{
-       struct ti_pipe3 *phy = dev_get_drvdata(dev);
-
-       ti_pipe3_disable_clocks(phy);
-       return 0;
-}
-
-static int ti_pipe3_resume(struct device *dev)
-{
-       struct ti_pipe3 *phy = dev_get_drvdata(dev);
-       int ret;
-
-       ret = ti_pipe3_enable_clocks(phy);
-       if (ret)
-               return ret;
-
-       pm_runtime_disable(dev);
-       pm_runtime_set_active(dev);
-       pm_runtime_enable(dev);
-       return 0;
-}
-#endif
-
-static const struct dev_pm_ops ti_pipe3_pm_ops = {
-       SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
-                          ti_pipe3_runtime_resume, NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume)
-};
-
 static const struct of_device_id ti_pipe3_id_table[] = {
        {
                .compatible = "ti,phy-usb3",
@@ -592,7 +552,6 @@ static struct platform_driver ti_pipe3_driver = {
        .remove         = ti_pipe3_remove,
        .driver         = {
                .name   = "ti-pipe3",
-               .pm     = &ti_pipe3_pm_ops,
                .of_match_table = ti_pipe3_id_table,
        },
 };
index efcf2a2b3975c2cc35fda3806223f0578900d4c2..6177315ab74e5eb43cc92fa9d57c892fadce4b40 100644 (file)
@@ -473,6 +473,8 @@ static void bcm2835_gpio_irq_disable(struct irq_data *data)
 
        spin_lock_irqsave(&pc->irq_lock[bank], flags);
        bcm2835_gpio_irq_config(pc, gpio, false);
+       /* Clear events that were latched prior to clearing event sources */
+       bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
        clear_bit(offset, &pc->enabled_irq_map[bank]);
        spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
 }
index 5fd4437cee1584a6cc7a5251269d1078a0b62ddf..88a7fac11bd499f72c831b91f0f6c05bd29b19f7 100644 (file)
@@ -403,14 +403,13 @@ static int imx1_pinconf_set(struct pinctrl_dev *pctldev,
                             unsigned num_configs)
 {
        struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx1_pinctrl_soc_info *info = ipctl->info;
        int i;
 
        for (i = 0; i != num_configs; ++i) {
                imx1_write_bit(ipctl, pin_id, configs[i] & 0x01, MX1_PUEN);
 
                dev_dbg(ipctl->dev, "pinconf set pullup pin %s\n",
-                       info->pins[pin_id].name);
+                       pin_desc_get(pctldev, pin_id)->name);
        }
 
        return 0;
index 557d0f2a3031b1a0295fe60796ec17ea7817fc52..97681fac082e71f449874a4a5a21a68b07e27fc2 100644 (file)
@@ -787,7 +787,6 @@ static const struct pinmux_ops abx500_pinmux_ops = {
        .set_mux = abx500_pmx_set,
        .gpio_request_enable = abx500_gpio_request_enable,
        .gpio_disable_free = abx500_gpio_disable_free,
-       .strict = true,
 };
 
 static int abx500_get_groups_cnt(struct pinctrl_dev *pctldev)
index ef0b697639a71e397ec545d17f6fe9ae9cec445d..347c763a6a78762302c89559a5ff92b64ec55872 100644 (file)
@@ -823,7 +823,7 @@ static int lpc18xx_pconf_set_i2c0(struct pinctrl_dev *pctldev,
                break;
 
        case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
-               if (param)
+               if (param_val)
                        *reg &= ~(LPC18XX_SCU_I2C0_ZIF << shift);
                else
                        *reg |= (LPC18XX_SCU_I2C0_ZIF << shift);
@@ -876,7 +876,7 @@ static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev,
                break;
 
        case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
-               if (param)
+               if (param_val)
                        *reg &= ~LPC18XX_SCU_PIN_ZIF;
                else
                        *reg |= LPC18XX_SCU_PIN_ZIF;
index b2de09d3b1a0c8e14b03e23fcb0131e6f41022ee..0b8d480171a3dfea7af0aa8b03e346d56b80f6bb 100644 (file)
@@ -1760,7 +1760,8 @@ static int pcs_irq_init_chained_handler(struct pcs_device *pcs,
                int res;
 
                res = request_irq(pcs_soc->irq, pcs_irq_handler,
-                                 IRQF_SHARED | IRQF_NO_SUSPEND,
+                                 IRQF_SHARED | IRQF_NO_SUSPEND |
+                                 IRQF_NO_THREAD,
                                  name, pcs_soc);
                if (res) {
                        pcs_soc->irq = -1;
index 3dd5a3b2ac62344a19713e92d9e7ad8fa5cf2461..c760bf43d116cfaa83370d640deefd38abb9f407 100644 (file)
 #include "../core.h"
 #include "pinctrl-samsung.h"
 
-#define GROUP_SUFFIX           "-grp"
-#define GSUFFIX_LEN            sizeof(GROUP_SUFFIX)
-#define FUNCTION_SUFFIX                "-mux"
-#define FSUFFIX_LEN            sizeof(FUNCTION_SUFFIX)
-
 /* list of all possible config options supported */
 static struct pin_config {
        const char *property;
index c7508d5f688613b26e6eb226628f61ba9cd38f66..0874cfee6889afa149fc18895de55c12ac2e5ff0 100644 (file)
@@ -224,7 +224,7 @@ struct sh_pfc_soc_info {
 
 /* PINMUX_GPIO_GP_ALL - Expand to a list of sh_pfc_pin entries */
 #define _GP_GPIO(bank, _pin, _name, sfx)                               \
-       [(bank * 32) + _pin] = {                                        \
+       {                                                               \
                .pin = (bank * 32) + _pin,                              \
                .name = __stringify(_name),                             \
                .enum_id = _name##_DATA,                                \
index cb13299195271ffed4854ed6b0b593c5e8487019..3271cd1abe7c0e6c5d2e813171aa5df494f9d977 100644 (file)
@@ -4,7 +4,6 @@
 
 menuconfig CHROME_PLATFORMS
        bool "Platform support for Chrome hardware"
-       depends on X86 || ARM
        ---help---
          Say Y here to get to see options for platform support for
          various Chromebooks and Chromeboxes. This option alone does
index 832932bdc977d21e84f2f8f563ce8aa937c64bc1..7fd4f511d78fd6bdc685c857e280f1581d20b035 100644 (file)
@@ -130,7 +130,7 @@ struct pm800_regulators {
                .owner  = THIS_MODULE,                                  \
                .n_voltages = ARRAY_SIZE(ldo_volt_table),               \
                .vsel_reg       = PM800_##vreg##_VOUT,                  \
-               .vsel_mask      = 0x1f,                                 \
+               .vsel_mask      = 0xf,                                  \
                .enable_reg     = PM800_##ereg,                         \
                .enable_mask    = 1 << (ebit),                          \
                .volt_table     = ldo_volt_table,                       \
index c9f72019bd689afbb4e51528932689dc097b191b..78387a6cbae59e40a6fb05fc255647cacfe3209b 100644 (file)
@@ -109,6 +109,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 static struct regulator *create_regulator(struct regulator_dev *rdev,
                                          struct device *dev,
                                          const char *supply_name);
+static void _regulator_put(struct regulator *regulator);
 
 static const char *rdev_get_name(struct regulator_dev *rdev)
 {
@@ -1105,6 +1106,9 @@ static int set_supply(struct regulator_dev *rdev,
 
        rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev));
 
+       if (!try_module_get(supply_rdev->owner))
+               return -ENODEV;
+
        rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY");
        if (rdev->supply == NULL) {
                err = -ENOMEM;
@@ -1381,9 +1385,13 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
        }
 
        if (!r) {
-               dev_err(dev, "Failed to resolve %s-supply for %s\n",
-                       rdev->supply_name, rdev->desc->name);
-               return -EPROBE_DEFER;
+               if (have_full_constraints()) {
+                       r = dummy_regulator_rdev;
+               } else {
+                       dev_err(dev, "Failed to resolve %s-supply for %s\n",
+                               rdev->supply_name, rdev->desc->name);
+                       return -EPROBE_DEFER;
+               }
        }
 
        /* Recursively resolve the supply of the supply */
@@ -1398,8 +1406,11 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
        /* Cascade always-on state to supply */
        if (_regulator_is_enabled(rdev)) {
                ret = regulator_enable(rdev->supply);
-               if (ret < 0)
+               if (ret < 0) {
+                       if (rdev->supply)
+                               _regulator_put(rdev->supply);
                        return ret;
+               }
        }
 
        return 0;
index 6f2bdad8b4d8fd6ce2e552d4c44c8cf4a3ee60ba..e94ddcf97722331e3cdde0645697169a35ba8c12 100644 (file)
@@ -450,7 +450,7 @@ static struct max8973_regulator_platform_data *max8973_parse_dt(
                pdata->control_flags  |= MAX8973_CONTROL_FREQ_SHIFT_9PER_ENABLE;
 
        if (of_property_read_bool(np, "maxim,enable-bias-control"))
-               pdata->control_flags  |= MAX8973_BIAS_ENABLE;
+               pdata->control_flags  |= MAX8973_CONTROL_BIAS_ENABLE;
 
        return pdata;
 }
index 326ffb55337117d6dc2a96d7fce9cea773e18a14..72fc3c32db49828ce6a2a9256ecabd01bdb034e8 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/mfd/samsung/s2mps14.h>
 #include <linux/mfd/samsung/s2mpu02.h>
 
+/* The highest number of possible regulators for supported devices. */
+#define S2MPS_REGULATOR_MAX            S2MPS13_REGULATOR_MAX
 struct s2mps11_info {
        unsigned int rdev_num;
        int ramp_delay2;
@@ -49,7 +51,7 @@ struct s2mps11_info {
         * One bit for each S2MPS13/S2MPS14/S2MPU02 regulator whether
         * the suspend mode was enabled.
         */
-       unsigned long long s2mps14_suspend_state:50;
+       DECLARE_BITMAP(suspend_state, S2MPS_REGULATOR_MAX);
 
        /* Array of size rdev_num with GPIO-s for external sleep control */
        int *ext_control_gpio;
@@ -500,7 +502,7 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev)
        switch (s2mps11->dev_type) {
        case S2MPS13X:
        case S2MPS14X:
-               if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
+               if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state))
                        val = S2MPS14_ENABLE_SUSPEND;
                else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)]))
                        val = S2MPS14_ENABLE_EXT_CONTROL;
@@ -508,7 +510,7 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev)
                        val = rdev->desc->enable_mask;
                break;
        case S2MPU02:
-               if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
+               if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state))
                        val = S2MPU02_ENABLE_SUSPEND;
                else
                        val = rdev->desc->enable_mask;
@@ -562,7 +564,7 @@ static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev)
        if (ret < 0)
                return ret;
 
-       s2mps11->s2mps14_suspend_state |= (1 << rdev_get_id(rdev));
+       set_bit(rdev_get_id(rdev), s2mps11->suspend_state);
        /*
         * Don't enable suspend mode if regulator is already disabled because
         * this would effectively for a short time turn on the regulator after
@@ -960,18 +962,22 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
        case S2MPS11X:
                s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators);
                regulators = s2mps11_regulators;
+               BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
                break;
        case S2MPS13X:
                s2mps11->rdev_num = ARRAY_SIZE(s2mps13_regulators);
                regulators = s2mps13_regulators;
+               BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
                break;
        case S2MPS14X:
                s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators);
                regulators = s2mps14_regulators;
+               BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
                break;
        case S2MPU02:
                s2mps11->rdev_num = ARRAY_SIZE(s2mpu02_regulators);
                regulators = s2mpu02_regulators;
+               BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
                break;
        default:
                dev_err(&pdev->dev, "Invalid device type: %u\n",
index 95bccfd3f169a8a3a167368f972cbbd08de7c869..e5225ad9c5b12fdd9d723704d66eb9ec2ff5b734 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the S/390 specific device drivers
 #
 
-obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/
+obj-y += cio/ block/ char/ crypto/ net/ scsi/ virtio/
 
 drivers-y += drivers/s390/built-in.o
 
index 882744852aacb822aa3264bf75fe761b2d494c9f..a9aa38903efefeeccf1dff34ad201af7283d70d9 100644 (file)
@@ -599,9 +599,10 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
 {
        struct ipr_trace_entry *trace_entry;
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       unsigned int trace_index;
 
-       trace_entry = &ioa_cfg->trace[atomic_add_return
-                       (1, &ioa_cfg->trace_index)%IPR_NUM_TRACE_ENTRIES];
+       trace_index = atomic_add_return(1, &ioa_cfg->trace_index) & IPR_TRACE_INDEX_MASK;
+       trace_entry = &ioa_cfg->trace[trace_index];
        trace_entry->time = jiffies;
        trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0];
        trace_entry->type = type;
@@ -1051,10 +1052,15 @@ static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd,
 
 static int ipr_get_hrrq_index(struct ipr_ioa_cfg *ioa_cfg)
 {
+       unsigned int hrrq;
+
        if (ioa_cfg->hrrq_num == 1)
-               return 0;
-       else
-               return (atomic_add_return(1, &ioa_cfg->hrrq_index) % (ioa_cfg->hrrq_num - 1)) + 1;
+               hrrq = 0;
+       else {
+               hrrq = atomic_add_return(1, &ioa_cfg->hrrq_index);
+               hrrq = (hrrq % (ioa_cfg->hrrq_num - 1)) + 1;
+       }
+       return hrrq;
 }
 
 /**
@@ -6263,21 +6269,23 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
        u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
-       unsigned long hrrq_flags;
+       unsigned long lock_flags;
 
        scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->s.ioasa.hdr.residual_data_len));
 
        if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
                scsi_dma_unmap(scsi_cmd);
 
-               spin_lock_irqsave(ipr_cmd->hrrq->lock, hrrq_flags);
+               spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags);
                list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
                scsi_cmd->scsi_done(scsi_cmd);
-               spin_unlock_irqrestore(ipr_cmd->hrrq->lock, hrrq_flags);
+               spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags);
        } else {
-               spin_lock_irqsave(ipr_cmd->hrrq->lock, hrrq_flags);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+               spin_lock(&ipr_cmd->hrrq->_lock);
                ipr_erp_start(ioa_cfg, ipr_cmd);
-               spin_unlock_irqrestore(ipr_cmd->hrrq->lock, hrrq_flags);
+               spin_unlock(&ipr_cmd->hrrq->_lock);
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
        }
 }
 
index 73790a1d096902fbda79f39ca7bd5c1bd43a1119..6b97ee45c7b460d0719f99baa011a6e13706aa67 100644 (file)
@@ -1486,6 +1486,7 @@ struct ipr_ioa_cfg {
 
 #define IPR_NUM_TRACE_INDEX_BITS       8
 #define IPR_NUM_TRACE_ENTRIES          (1 << IPR_NUM_TRACE_INDEX_BITS)
+#define IPR_TRACE_INDEX_MASK           (IPR_NUM_TRACE_ENTRIES - 1)
 #define IPR_TRACE_SIZE (sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES)
        char trace_start[8];
 #define IPR_TRACE_START_LABEL                  "trace"
index 1b3a094734522803c7f3fecd39da5c297a1feb43..30f9ef0c0d4f8cea52b182f370a04ed1ba4a9908 100644 (file)
@@ -733,8 +733,6 @@ static bool fc_invoke_resp(struct fc_exch *ep, struct fc_seq *sp,
        if (resp) {
                resp(sp, fp, arg);
                res = true;
-       } else if (!IS_ERR(fp)) {
-               fc_frame_free(fp);
        }
 
        spin_lock_bh(&ep->ex_lock);
@@ -1596,7 +1594,8 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
         * If new exch resp handler is valid then call that
         * first.
         */
-       fc_invoke_resp(ep, sp, fp);
+       if (!fc_invoke_resp(ep, sp, fp))
+               fc_frame_free(fp);
 
        fc_exch_release(ep);
        return;
@@ -1695,7 +1694,8 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp)
        fc_exch_hold(ep);
        if (!rc)
                fc_exch_delete(ep);
-       fc_invoke_resp(ep, sp, fp);
+       if (!fc_invoke_resp(ep, sp, fp))
+               fc_frame_free(fp);
        if (has_rec)
                fc_exch_timer_set(ep, ep->r_a_tov);
        fc_exch_release(ep);
index c6795941b45d98579cd6117cc5b72f8c5c4d0bf9..2d5909c4685ca63375f5041d960effada171f5fc 100644 (file)
@@ -1039,11 +1039,26 @@ restart:
                fc_fcp_pkt_hold(fsp);
                spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
 
-               if (!fc_fcp_lock_pkt(fsp)) {
+               spin_lock_bh(&fsp->scsi_pkt_lock);
+               if (!(fsp->state & FC_SRB_COMPL)) {
+                       fsp->state |= FC_SRB_COMPL;
+                       /*
+                        * TODO: dropping scsi_pkt_lock and then reacquiring
+                        * again around fc_fcp_cleanup_cmd() is required,
+                        * since fc_fcp_cleanup_cmd() calls into
+                        * fc_seq_set_resp() and that func preempts cpu using
+                        * schedule. May be schedule and related code should be
+                        * removed instead of unlocking here to avoid scheduling
+                        * while atomic bug.
+                        */
+                       spin_unlock_bh(&fsp->scsi_pkt_lock);
+
                        fc_fcp_cleanup_cmd(fsp, error);
+
+                       spin_lock_bh(&fsp->scsi_pkt_lock);
                        fc_io_compl(fsp);
-                       fc_fcp_unlock_pkt(fsp);
                }
+               spin_unlock_bh(&fsp->scsi_pkt_lock);
 
                fc_fcp_pkt_release(fsp);
                spin_lock_irqsave(&si->scsi_queue_lock, flags);
index 8053f24f03499335112721cd50c2816da40393a6..98d9bb6ff725ff46621a408bdf1f208175e21daf 100644 (file)
@@ -2941,10 +2941,10 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
 {
        struct iscsi_conn *conn = cls_conn->dd_data;
        struct iscsi_session *session = conn->session;
-       unsigned long flags;
 
        del_timer_sync(&conn->transport_timer);
 
+       mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->frwd_lock);
        conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
        if (session->leadconn == conn) {
@@ -2956,28 +2956,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        }
        spin_unlock_bh(&session->frwd_lock);
 
-       /*
-        * Block until all in-progress commands for this connection
-        * time out or fail.
-        */
-       for (;;) {
-               spin_lock_irqsave(session->host->host_lock, flags);
-               if (!atomic_read(&session->host->host_busy)) { /* OK for ERL == 0 */
-                       spin_unlock_irqrestore(session->host->host_lock, flags);
-                       break;
-               }
-               spin_unlock_irqrestore(session->host->host_lock, flags);
-               msleep_interruptible(500);
-               iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
-                                 "host_busy %d host_failed %d\n",
-                                 atomic_read(&session->host->host_busy),
-                                 session->host->host_failed);
-               /*
-                * force eh_abort() to unblock
-                */
-               wake_up(&conn->ehwait);
-       }
-
        /* flush queued up work because we free the connection below */
        iscsi_suspend_tx(conn);
 
@@ -2994,6 +2972,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        if (session->leadconn == conn)
                session->leadconn = NULL;
        spin_unlock_bh(&session->frwd_lock);
+       mutex_unlock(&session->eh_mutex);
 
        iscsi_destroy_conn(cls_conn);
 }
index 82b92c414a9cfe3152933e9cfc191c79c480568c..437254e1c4dee0c9972ff723ad31575911002993 100644 (file)
@@ -738,7 +738,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
                ql_log(ql_log_info, vha, 0x706f,
                    "Issuing MPI reset.\n");
 
-               if (IS_QLA83XX(ha)) {
+               if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
                        uint32_t idc_control;
 
                        qla83xx_idc_lock(vha, 0);
index 0e6ee3ca30e667591db375ba73d9009b286ec93b..8b011aef12bd5ec6e72f5d7a57bfa2285ae64404 100644 (file)
  * |                              |                    | 0xd031-0xd0ff |
  * |                              |                    | 0xd101-0xd1fe |
  * |                              |                    | 0xd214-0xd2fe |
- * | Target Mode                 |       0xe079       |                |
- * | Target Mode Management      |       0xf072       | 0xf002         |
+ * | Target Mode                 |       0xe080       |                |
+ * | Target Mode Management      |       0xf096       | 0xf002         |
  * |                              |                    | 0xf046-0xf049  |
- * | Target Mode Task Management  |      0x1000b      |                |
+ * | Target Mode Task Management  |      0x1000d      |                |
  * ----------------------------------------------------------------------
  */
 
index e86201d3b8c6d9eccbd1132e96cffb08310b7988..9ad819edcd67af2c73ca5a0a85a8863398b3c6f7 100644 (file)
 #define RESPONSE_ENTRY_CNT_FX00                256     /* Number of response entries.*/
 
 struct req_que;
+struct qla_tgt_sess;
 
 /*
  * (sd.h is not exported, hence local inclusion)
@@ -2026,6 +2027,7 @@ typedef struct fc_port {
        uint16_t port_id;
 
        unsigned long retry_delay_timestamp;
+       struct qla_tgt_sess *tgt_session;
 } fc_port_t;
 
 #include "qla_mr.h"
@@ -3154,13 +3156,13 @@ struct qla_hw_data {
 /* Bit 21 of fw_attributes decides the MCTP capabilities */
 #define IS_MCTP_CAPABLE(ha)    (IS_QLA2031(ha) && \
                                ((ha)->fw_attributes_ext[0] & BIT_0))
-#define IS_PI_UNINIT_CAPABLE(ha)       (IS_QLA83XX(ha))
-#define IS_PI_IPGUARD_CAPABLE(ha)      (IS_QLA83XX(ha))
+#define IS_PI_UNINIT_CAPABLE(ha)       (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+#define IS_PI_IPGUARD_CAPABLE(ha)      (IS_QLA83XX(ha) || IS_QLA27XX(ha))
 #define IS_PI_DIFB_DIX0_CAPABLE(ha)    (0)
-#define IS_PI_SPLIT_DET_CAPABLE_HBA(ha)        (IS_QLA83XX(ha))
+#define IS_PI_SPLIT_DET_CAPABLE_HBA(ha)        (IS_QLA83XX(ha) || IS_QLA27XX(ha))
 #define IS_PI_SPLIT_DET_CAPABLE(ha)    (IS_PI_SPLIT_DET_CAPABLE_HBA(ha) && \
     (((ha)->fw_attributes_h << 16 | (ha)->fw_attributes) & BIT_22))
-#define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha))
+#define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha))
 #define IS_TGT_MODE_CAPABLE(ha)        (ha->tgt.atio_q_length)
 #define IS_SHADOW_REG_CAPABLE(ha)  (IS_QLA27XX(ha))
 #define IS_DPORT_CAPABLE(ha)  (IS_QLA83XX(ha) || IS_QLA27XX(ha))
@@ -3579,6 +3581,16 @@ typedef struct scsi_qla_host {
        uint16_t        fcoe_fcf_idx;
        uint8_t         fcoe_vn_port_mac[6];
 
+       /* list of commands waiting on workqueue */
+       struct list_head        qla_cmd_list;
+       struct list_head        qla_sess_op_cmd_list;
+       spinlock_t              cmd_list_lock;
+
+       /* Counter to detect races between ELS and RSCN events */
+       atomic_t                generation_tick;
+       /* Time when global fcport update has been scheduled */
+       int                     total_fcport_update_gen;
+
        uint32_t        vp_abort_cnt;
 
        struct fc_vport *fc_vport;      /* holds fc_vport * for each vport */
index 664013115c9da7d7912d0b22fa34ddf91e7b977b..11f2f3279eab2984fe131510cc669b329f149bae 100644 (file)
@@ -115,6 +115,8 @@ qla2x00_async_iocb_timeout(void *data)
                        QLA_LOGIO_LOGIN_RETRIED : 0;
                qla2x00_post_async_login_done_work(fcport->vha, fcport,
                        lio->u.logio.data);
+       } else if (sp->type == SRB_LOGOUT_CMD) {
+               qlt_logo_completion_handler(fcport, QLA_FUNCTION_TIMEOUT);
        }
 }
 
@@ -497,7 +499,10 @@ void
 qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
 {
-       qla2x00_mark_device_lost(vha, fcport, 1, 0);
+       /* Don't re-login in target mode */
+       if (!fcport->tgt_session)
+               qla2x00_mark_device_lost(vha, fcport, 1, 0);
+       qlt_logo_completion_handler(fcport, data[0]);
        return;
 }
 
@@ -1538,7 +1543,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
                mem_size = (ha->fw_memory_size - 0x11000 + 1) *
                    sizeof(uint16_t);
        } else if (IS_FWI2_CAPABLE(ha)) {
-               if (IS_QLA83XX(ha))
+               if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
                        fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem);
                else if (IS_QLA81XX(ha))
                        fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
@@ -1550,7 +1555,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
                mem_size = (ha->fw_memory_size - 0x100000 + 1) *
                    sizeof(uint32_t);
                if (ha->mqenable) {
-                       if (!IS_QLA83XX(ha))
+                       if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
                                mq_size = sizeof(struct qla2xxx_mq_chain);
                        /*
                         * Allocate maximum buffer size for all queues.
@@ -2922,21 +2927,14 @@ qla2x00_rport_del(void *data)
 {
        fc_port_t *fcport = data;
        struct fc_rport *rport;
-       scsi_qla_host_t *vha = fcport->vha;
        unsigned long flags;
 
        spin_lock_irqsave(fcport->vha->host->host_lock, flags);
        rport = fcport->drport ? fcport->drport: fcport->rport;
        fcport->drport = NULL;
        spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
-       if (rport) {
+       if (rport)
                fc_remote_port_delete(rport);
-               /*
-                * Release the target mode FC NEXUS in qla_target.c code
-                * if target mod is enabled.
-                */
-               qlt_fc_port_deleted(vha, fcport);
-       }
 }
 
 /**
@@ -3303,6 +3301,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
         * Create target mode FC NEXUS in qla_target.c if target mode is
         * enabled..
         */
+
        qlt_fc_port_added(vha, fcport);
 
        spin_lock_irqsave(fcport->vha->host->host_lock, flags);
@@ -3341,8 +3340,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
 
        if (IS_QLAFX00(vha->hw)) {
                qla2x00_set_fcport_state(fcport, FCS_ONLINE);
-               qla2x00_reg_remote_port(vha, fcport);
-               return;
+               goto reg_port;
        }
        fcport->login_retry = 0;
        fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
@@ -3350,7 +3348,16 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
        qla2x00_set_fcport_state(fcport, FCS_ONLINE);
        qla2x00_iidma_fcport(vha, fcport);
        qla24xx_update_fcport_fcp_prio(vha, fcport);
-       qla2x00_reg_remote_port(vha, fcport);
+
+reg_port:
+       if (qla_ini_mode_enabled(vha))
+               qla2x00_reg_remote_port(vha, fcport);
+       else {
+               /*
+                * Create target mode FC NEXUS in qla_target.c
+                */
+               qlt_fc_port_added(vha, fcport);
+       }
 }
 
 /*
@@ -3375,6 +3382,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
        LIST_HEAD(new_fcports);
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
+       int             discovery_gen;
 
        /* If FL port exists, then SNS is present */
        if (IS_FWI2_CAPABLE(ha))
@@ -3445,6 +3453,14 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                        fcport->scan_state = QLA_FCPORT_SCAN;
                }
 
+               /* Mark the time right before querying FW for connected ports.
+                * This process is long, asynchronous and by the time it's done,
+                * collected information might not be accurate anymore. E.g.
+                * disconnected port might have re-connected and a brand new
+                * session has been created. In this case session's generation
+                * will be newer than discovery_gen. */
+               qlt_do_generation_tick(vha, &discovery_gen);
+
                rval = qla2x00_find_all_fabric_devs(vha, &new_fcports);
                if (rval != QLA_SUCCESS)
                        break;
@@ -3460,20 +3476,44 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                        if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
                                continue;
 
-                       if (fcport->scan_state == QLA_FCPORT_SCAN &&
-                           atomic_read(&fcport->state) == FCS_ONLINE) {
-                               qla2x00_mark_device_lost(vha, fcport,
-                                   ql2xplogiabsentdevice, 0);
-                               if (fcport->loop_id != FC_NO_LOOP_ID &&
-                                   (fcport->flags & FCF_FCP2_DEVICE) == 0 &&
-                                   fcport->port_type != FCT_INITIATOR &&
-                                   fcport->port_type != FCT_BROADCAST) {
-                                       ha->isp_ops->fabric_logout(vha,
-                                           fcport->loop_id,
-                                           fcport->d_id.b.domain,
-                                           fcport->d_id.b.area,
-                                           fcport->d_id.b.al_pa);
-                                       qla2x00_clear_loop_id(fcport);
+                       if (fcport->scan_state == QLA_FCPORT_SCAN) {
+                               if (qla_ini_mode_enabled(base_vha) &&
+                                   atomic_read(&fcport->state) == FCS_ONLINE) {
+                                       qla2x00_mark_device_lost(vha, fcport,
+                                           ql2xplogiabsentdevice, 0);
+                                       if (fcport->loop_id != FC_NO_LOOP_ID &&
+                                           (fcport->flags & FCF_FCP2_DEVICE) == 0 &&
+                                           fcport->port_type != FCT_INITIATOR &&
+                                           fcport->port_type != FCT_BROADCAST) {
+                                               ha->isp_ops->fabric_logout(vha,
+                                                   fcport->loop_id,
+                                                   fcport->d_id.b.domain,
+                                                   fcport->d_id.b.area,
+                                                   fcport->d_id.b.al_pa);
+                                               qla2x00_clear_loop_id(fcport);
+                                       }
+                               } else if (!qla_ini_mode_enabled(base_vha)) {
+                                       /*
+                                        * In target mode, explicitly kill
+                                        * sessions and log out of devices
+                                        * that are gone, so that we don't
+                                        * end up with an initiator using the
+                                        * wrong ACL (if the fabric recycles
+                                        * an FC address and we have a stale
+                                        * session around) and so that we don't
+                                        * report initiators that are no longer
+                                        * on the fabric.
+                                        */
+                                       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf077,
+                                           "port gone, logging out/killing session: "
+                                           "%8phC state 0x%x flags 0x%x fc4_type 0x%x "
+                                           "scan_state %d\n",
+                                           fcport->port_name,
+                                           atomic_read(&fcport->state),
+                                           fcport->flags, fcport->fc4_type,
+                                           fcport->scan_state);
+                                       qlt_fc_port_deleted(vha, fcport,
+                                           discovery_gen);
                                }
                        }
                }
@@ -3494,6 +3534,28 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                            (fcport->flags & FCF_LOGIN_NEEDED) == 0)
                                continue;
 
+                       /*
+                        * If we're not an initiator, skip looking for devices
+                        * and logging in.  There's no reason for us to do it,
+                        * and it seems to actively cause problems in target
+                        * mode if we race with the initiator logging into us
+                        * (we might get the "port ID used" status back from
+                        * our login command and log out the initiator, which
+                        * seems to cause havoc).
+                        */
+                       if (!qla_ini_mode_enabled(base_vha)) {
+                               if (fcport->scan_state == QLA_FCPORT_FOUND) {
+                                       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf078,
+                                           "port %8phC state 0x%x flags 0x%x fc4_type 0x%x "
+                                           "scan_state %d (initiator mode disabled; skipping "
+                                           "login)\n", fcport->port_name,
+                                           atomic_read(&fcport->state),
+                                           fcport->flags, fcport->fc4_type,
+                                           fcport->scan_state);
+                               }
+                               continue;
+                       }
+
                        if (fcport->loop_id == FC_NO_LOOP_ID) {
                                fcport->loop_id = next_loopid;
                                rval = qla2x00_find_new_loop_id(
@@ -3520,16 +3582,38 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                            test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
                                break;
 
-                       /* Find a new loop ID to use. */
-                       fcport->loop_id = next_loopid;
-                       rval = qla2x00_find_new_loop_id(base_vha, fcport);
-                       if (rval != QLA_SUCCESS) {
-                               /* Ran out of IDs to use */
-                               break;
-                       }
+                       /*
+                        * If we're not an initiator, skip looking for devices
+                        * and logging in.  There's no reason for us to do it,
+                        * and it seems to actively cause problems in target
+                        * mode if we race with the initiator logging into us
+                        * (we might get the "port ID used" status back from
+                        * our login command and log out the initiator, which
+                        * seems to cause havoc).
+                        */
+                       if (qla_ini_mode_enabled(base_vha)) {
+                               /* Find a new loop ID to use. */
+                               fcport->loop_id = next_loopid;
+                               rval = qla2x00_find_new_loop_id(base_vha,
+                                   fcport);
+                               if (rval != QLA_SUCCESS) {
+                                       /* Ran out of IDs to use */
+                                       break;
+                               }
 
-                       /* Login and update database */
-                       qla2x00_fabric_dev_login(vha, fcport, &next_loopid);
+                               /* Login and update database */
+                               qla2x00_fabric_dev_login(vha, fcport,
+                                   &next_loopid);
+                       } else {
+                               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf079,
+                                       "new port %8phC state 0x%x flags 0x%x fc4_type "
+                                       "0x%x scan_state %d (initiator mode disabled; "
+                                       "skipping login)\n",
+                                       fcport->port_name,
+                                       atomic_read(&fcport->state),
+                                       fcport->flags, fcport->fc4_type,
+                                       fcport->scan_state);
+                       }
 
                        list_move_tail(&fcport->list, &vha->vp_fcports);
                }
@@ -3725,11 +3809,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                        fcport->fp_speed = new_fcport->fp_speed;
 
                        /*
-                        * If address the same and state FCS_ONLINE, nothing
-                        * changed.
+                        * If address the same and state FCS_ONLINE
+                        * (or in target mode), nothing changed.
                         */
                        if (fcport->d_id.b24 == new_fcport->d_id.b24 &&
-                           atomic_read(&fcport->state) == FCS_ONLINE) {
+                           (atomic_read(&fcport->state) == FCS_ONLINE ||
+                            !qla_ini_mode_enabled(base_vha))) {
                                break;
                        }
 
@@ -3749,6 +3834,22 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                         * Log it out if still logged in and mark it for
                         * relogin later.
                         */
+                       if (!qla_ini_mode_enabled(base_vha)) {
+                               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf080,
+                                        "port changed FC ID, %8phC"
+                                        " old %x:%x:%x (loop_id 0x%04x)-> new %x:%x:%x\n",
+                                        fcport->port_name,
+                                        fcport->d_id.b.domain,
+                                        fcport->d_id.b.area,
+                                        fcport->d_id.b.al_pa,
+                                        fcport->loop_id,
+                                        new_fcport->d_id.b.domain,
+                                        new_fcport->d_id.b.area,
+                                        new_fcport->d_id.b.al_pa);
+                               fcport->d_id.b24 = new_fcport->d_id.b24;
+                               break;
+                       }
+
                        fcport->d_id.b24 = new_fcport->d_id.b24;
                        fcport->flags |= FCF_LOGIN_NEEDED;
                        if (fcport->loop_id != FC_NO_LOOP_ID &&
@@ -3768,6 +3869,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                if (found)
                        continue;
                /* If device was not in our fcports list, then add it. */
+               new_fcport->scan_state = QLA_FCPORT_FOUND;
                list_add_tail(&new_fcport->list, new_fcports);
 
                /* Allocate a new replacement fcport. */
@@ -4188,6 +4290,14 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
                            atomic_read(&fcport->state) != FCS_UNCONFIGURED) {
                                spin_unlock_irqrestore(&ha->vport_slock, flags);
                                qla2x00_rport_del(fcport);
+
+                               /*
+                                * Release the target mode FC NEXUS in
+                                * qla_target.c, if target mod is enabled.
+                                */
+                               qlt_fc_port_deleted(vha, fcport,
+                                   base_vha->total_fcport_update_gen);
+
                                spin_lock_irqsave(&ha->vport_slock, flags);
                        }
                }
index 36fbd4c7af8f50e52cd0289bc31d9ccfca8bbe24..6f02b26a35cff5b06916273a0bf1c8643f523689 100644 (file)
@@ -1943,6 +1943,9 @@ qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio)
        logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
        logio->control_flags =
            cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO);
+       if (!sp->fcport->tgt_session ||
+           !sp->fcport->tgt_session->keep_nport_handle)
+               logio->control_flags |= cpu_to_le16(LCF_FREE_NPORT);
        logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
        logio->port_id[0] = sp->fcport->d_id.b.al_pa;
        logio->port_id[1] = sp->fcport->d_id.b.area;
index 02b1c1c5355b948db22e1e69d2ae513387d198fa..b2f713ad90346093b40b515b70be4062666c6b80 100644 (file)
@@ -2415,7 +2415,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
                        *orig_iocb_cnt = mcp->mb[10];
                if (vha->hw->flags.npiv_supported && max_npiv_vports)
                        *max_npiv_vports = mcp->mb[11];
-               if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw)) && max_fcfs)
+               if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) ||
+                   IS_QLA27XX(vha->hw)) && max_fcfs)
                        *max_fcfs = mcp->mb[12];
        }
 
@@ -3898,7 +3899,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
        spin_lock_irqsave(&ha->hardware_lock, flags);
        if (!(rsp->options & BIT_0)) {
                WRT_REG_DWORD(rsp->rsp_q_out, 0);
-               if (!IS_QLA83XX(ha))
+               if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
                        WRT_REG_DWORD(rsp->rsp_q_in, 0);
        }
 
@@ -5345,7 +5346,7 @@ qla83xx_restart_nic_firmware(scsi_qla_host_t *vha)
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
-       if (!IS_QLA83XX(ha))
+       if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
                return QLA_FUNCTION_FAILED;
 
        ql_dbg(ql_dbg_mbx, vha, 0x1143, "Entered %s.\n", __func__);
index a28815b8276f090901498dafaf39d12c97db42eb..8a5cac8448c76518107d95744b39ea76717958f5 100644 (file)
@@ -2504,6 +2504,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->mbx_count = MAILBOX_REGISTER_COUNT;
                req_length = REQUEST_ENTRY_CNT_24XX;
                rsp_length = RESPONSE_ENTRY_CNT_2300;
+               ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
                ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
                ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
                ha->gid_list_info_size = 8;
@@ -3229,11 +3230,15 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
                spin_lock_irqsave(vha->host->host_lock, flags);
                fcport->drport = rport;
                spin_unlock_irqrestore(vha->host->host_lock, flags);
+               qlt_do_generation_tick(vha, &base_vha->total_fcport_update_gen);
                set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
                qla2xxx_wake_dpc(base_vha);
        } else {
-               fc_remote_port_delete(rport);
-               qlt_fc_port_deleted(vha, fcport);
+               int now;
+               if (rport)
+                       fc_remote_port_delete(rport);
+               qlt_do_generation_tick(vha, &now);
+               qlt_fc_port_deleted(vha, fcport, now);
        }
 }
 
@@ -3763,8 +3768,11 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
        INIT_LIST_HEAD(&vha->vp_fcports);
        INIT_LIST_HEAD(&vha->work_list);
        INIT_LIST_HEAD(&vha->list);
+       INIT_LIST_HEAD(&vha->qla_cmd_list);
+       INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list);
 
        spin_lock_init(&vha->work_lock);
+       spin_lock_init(&vha->cmd_list_lock);
 
        sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no);
        ql_dbg(ql_dbg_init, vha, 0x0041,
index 028e8c8a7de9a897ac68ad8c09a2d47be0276f5c..2feb5f38edcd98ec3607f18a020d1cedee5bfc40 100644 (file)
@@ -1697,7 +1697,7 @@ qla83xx_select_led_port(struct qla_hw_data *ha)
 {
        uint32_t led_select_value = 0;
 
-       if (!IS_QLA83XX(ha))
+       if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
                goto out;
 
        if (ha->port_no == 0)
index b749026aa592445d70dd51056314ff29965578ca..58651ecbd88c206e0be3b996c007baeaddc8cb19 100644 (file)
@@ -113,6 +113,11 @@ static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
 static void qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
        struct atio_from_isp *atio, uint16_t status, int qfull);
 static void qlt_disable_vha(struct scsi_qla_host *vha);
+static void qlt_clear_tgt_db(struct qla_tgt *tgt);
+static void qlt_send_notify_ack(struct scsi_qla_host *vha,
+       struct imm_ntfy_from_isp *ntfy,
+       uint32_t add_flags, uint16_t resp_code, int resp_code_valid,
+       uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan);
 /*
  * Global Variables
  */
@@ -122,6 +127,16 @@ static struct workqueue_struct *qla_tgt_wq;
 static DEFINE_MUTEX(qla_tgt_mutex);
 static LIST_HEAD(qla_tgt_glist);
 
+/* This API intentionally takes dest as a parameter, rather than returning
+ * int value to avoid caller forgetting to issue wmb() after the store */
+void qlt_do_generation_tick(struct scsi_qla_host *vha, int *dest)
+{
+       scsi_qla_host_t *base_vha = pci_get_drvdata(vha->hw->pdev);
+       *dest = atomic_inc_return(&base_vha->generation_tick);
+       /* memory barrier */
+       wmb();
+}
+
 /* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list) */
 static struct qla_tgt_sess *qlt_find_sess_by_port_name(
        struct qla_tgt *tgt,
@@ -381,14 +396,73 @@ static void qlt_free_session_done(struct work_struct *work)
        struct qla_tgt *tgt = sess->tgt;
        struct scsi_qla_host *vha = sess->vha;
        struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
+       bool logout_started = false;
+       fc_port_t fcport;
+
+       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
+               "%s: se_sess %p / sess %p from port %8phC loop_id %#04x"
+               " s_id %02x:%02x:%02x logout %d keep %d plogi %d\n",
+               __func__, sess->se_sess, sess, sess->port_name, sess->loop_id,
+               sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
+               sess->logout_on_delete, sess->keep_nport_handle,
+               sess->plogi_ack_needed);
 
        BUG_ON(!tgt);
+
+       if (sess->logout_on_delete) {
+               int rc;
+
+               memset(&fcport, 0, sizeof(fcport));
+               fcport.loop_id = sess->loop_id;
+               fcport.d_id = sess->s_id;
+               memcpy(fcport.port_name, sess->port_name, WWN_SIZE);
+               fcport.vha = vha;
+               fcport.tgt_session = sess;
+
+               rc = qla2x00_post_async_logout_work(vha, &fcport, NULL);
+               if (rc != QLA_SUCCESS)
+                       ql_log(ql_log_warn, vha, 0xf085,
+                              "Schedule logo failed sess %p rc %d\n",
+                              sess, rc);
+               else
+                       logout_started = true;
+       }
+
        /*
         * Release the target session for FC Nexus from fabric module code.
         */
        if (sess->se_sess != NULL)
                ha->tgt.tgt_ops->free_session(sess);
 
+       if (logout_started) {
+               bool traced = false;
+
+               while (!ACCESS_ONCE(sess->logout_completed)) {
+                       if (!traced) {
+                               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf086,
+                                       "%s: waiting for sess %p logout\n",
+                                       __func__, sess);
+                               traced = true;
+                       }
+                       msleep(100);
+               }
+
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf087,
+                       "%s: sess %p logout completed\n",
+                       __func__, sess);
+       }
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+
+       if (sess->plogi_ack_needed)
+               qlt_send_notify_ack(vha, &sess->tm_iocb,
+                                   0, 0, 0, 0, 0, 0);
+
+       list_del(&sess->sess_list_entry);
+
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf001,
            "Unregistration of sess %p finished\n", sess);
 
@@ -409,9 +483,9 @@ void qlt_unreg_sess(struct qla_tgt_sess *sess)
 
        vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess);
 
-       list_del(&sess->sess_list_entry);
-       if (sess->deleted)
-               list_del(&sess->del_list_entry);
+       if (!list_empty(&sess->del_list_entry))
+               list_del_init(&sess->del_list_entry);
+       sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
 
        INIT_WORK(&sess->free_work, qlt_free_session_done);
        schedule_work(&sess->free_work);
@@ -431,10 +505,10 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
 
        loop_id = le16_to_cpu(n->u.isp24.nport_handle);
        if (loop_id == 0xFFFF) {
-#if 0 /* FIXME: Re-enable Global event handling.. */
                /* Global event */
-               atomic_inc(&ha->tgt.qla_tgt->tgt_global_resets_count);
-               qlt_clear_tgt_db(ha->tgt.qla_tgt);
+               atomic_inc(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
+               qlt_clear_tgt_db(vha->vha_tgt.qla_tgt);
+#if 0 /* FIXME: do we need to choose a session here? */
                if (!list_empty(&ha->tgt.qla_tgt->sess_list)) {
                        sess = list_entry(ha->tgt.qla_tgt->sess_list.next,
                            typeof(*sess), sess_list_entry);
@@ -489,27 +563,38 @@ static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
        struct qla_tgt *tgt = sess->tgt;
        uint32_t dev_loss_tmo = tgt->ha->port_down_retry_count + 5;
 
-       if (sess->deleted)
-               return;
+       if (sess->deleted) {
+               /* Upgrade to unconditional deletion in case it was temporary */
+               if (immediate && sess->deleted == QLA_SESS_DELETION_PENDING)
+                       list_del(&sess->del_list_entry);
+               else
+                       return;
+       }
 
        ql_dbg(ql_dbg_tgt, sess->vha, 0xe001,
            "Scheduling sess %p for deletion\n", sess);
-       list_add_tail(&sess->del_list_entry, &tgt->del_sess_list);
-       sess->deleted = 1;
 
-       if (immediate)
+       if (immediate) {
                dev_loss_tmo = 0;
+               sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
+               list_add(&sess->del_list_entry, &tgt->del_sess_list);
+       } else {
+               sess->deleted = QLA_SESS_DELETION_PENDING;
+               list_add_tail(&sess->del_list_entry, &tgt->del_sess_list);
+       }
 
        sess->expires = jiffies + dev_loss_tmo * HZ;
 
        ql_dbg(ql_dbg_tgt, sess->vha, 0xe048,
-           "qla_target(%d): session for port %8phC (loop ID %d) scheduled for "
-           "deletion in %u secs (expires: %lu) immed: %d\n",
-           sess->vha->vp_idx, sess->port_name, sess->loop_id, dev_loss_tmo,
-           sess->expires, immediate);
+           "qla_target(%d): session for port %8phC (loop ID %d s_id %02x:%02x:%02x)"
+           " scheduled for deletion in %u secs (expires: %lu) immed: %d, logout: %d, gen: %#x\n",
+           sess->vha->vp_idx, sess->port_name, sess->loop_id,
+           sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
+           dev_loss_tmo, sess->expires, immediate, sess->logout_on_delete,
+           sess->generation);
 
        if (immediate)
-               schedule_delayed_work(&tgt->sess_del_work, 0);
+               mod_delayed_work(system_wq, &tgt->sess_del_work, 0);
        else
                schedule_delayed_work(&tgt->sess_del_work,
                    sess->expires - jiffies);
@@ -578,9 +663,9 @@ out_free_id_list:
 /* ha->hardware_lock supposed to be held on entry */
 static void qlt_undelete_sess(struct qla_tgt_sess *sess)
 {
-       BUG_ON(!sess->deleted);
+       BUG_ON(sess->deleted != QLA_SESS_DELETION_PENDING);
 
-       list_del(&sess->del_list_entry);
+       list_del_init(&sess->del_list_entry);
        sess->deleted = 0;
 }
 
@@ -599,7 +684,9 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
                    del_list_entry);
                elapsed = jiffies;
                if (time_after_eq(elapsed, sess->expires)) {
-                       qlt_undelete_sess(sess);
+                       /* No turning back */
+                       list_del_init(&sess->del_list_entry);
+                       sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
 
                        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004,
                            "Timeout: sess %p about to be deleted\n",
@@ -643,6 +730,13 @@ static struct qla_tgt_sess *qlt_create_sess(
                            fcport->d_id.b.al_pa, fcport->d_id.b.area,
                            fcport->loop_id);
 
+                       /* Cannot undelete at this point */
+                       if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+                               spin_unlock_irqrestore(&ha->hardware_lock,
+                                   flags);
+                               return NULL;
+                       }
+
                        if (sess->deleted)
                                qlt_undelete_sess(sess);
 
@@ -652,6 +746,9 @@ static struct qla_tgt_sess *qlt_create_sess(
 
                        if (sess->local && !local)
                                sess->local = 0;
+
+                       qlt_do_generation_tick(vha, &sess->generation);
+
                        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
                        return sess;
@@ -673,6 +770,14 @@ static struct qla_tgt_sess *qlt_create_sess(
        sess->s_id = fcport->d_id;
        sess->loop_id = fcport->loop_id;
        sess->local = local;
+       INIT_LIST_HEAD(&sess->del_list_entry);
+
+       /* Under normal circumstances we want to logout from firmware when
+        * session eventually ends and release corresponding nport handle.
+        * In the exception cases (e.g. when new PLOGI is waiting) corresponding
+        * code will adjust these flags as necessary. */
+       sess->logout_on_delete = 1;
+       sess->keep_nport_handle = 0;
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf006,
            "Adding sess %p to tgt %p via ->check_initiator_node_acl()\n",
@@ -705,6 +810,7 @@ static struct qla_tgt_sess *qlt_create_sess(
        spin_lock_irqsave(&ha->hardware_lock, flags);
        list_add_tail(&sess->sess_list_entry, &vha->vha_tgt.qla_tgt->sess_list);
        vha->vha_tgt.qla_tgt->sess_count++;
+       qlt_do_generation_tick(vha, &sess->generation);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b,
@@ -718,7 +824,7 @@ static struct qla_tgt_sess *qlt_create_sess(
 }
 
 /*
- * Called from drivers/scsi/qla2xxx/qla_init.c:qla2x00_reg_remote_port()
+ * Called from qla2x00_reg_remote_port()
  */
 void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
 {
@@ -750,6 +856,10 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
                mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
                spin_lock_irqsave(&ha->hardware_lock, flags);
+       } else if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+               /* Point of no return */
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               return;
        } else {
                kref_get(&sess->se_sess->sess_kref);
 
@@ -780,27 +890,36 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
-void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport)
+/*
+ * max_gen - specifies maximum session generation
+ * at which this deletion requestion is still valid
+ */
+void
+qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
 {
-       struct qla_hw_data *ha = vha->hw;
        struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        struct qla_tgt_sess *sess;
-       unsigned long flags;
 
        if (!vha->hw->tgt.tgt_ops)
                return;
 
-       if (!tgt || (fcport->port_type != FCT_INITIATOR))
+       if (!tgt)
                return;
 
-       spin_lock_irqsave(&ha->hardware_lock, flags);
        if (tgt->tgt_stop) {
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
                return;
        }
        sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
        if (!sess) {
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               return;
+       }
+
+       if (max_gen - sess->generation < 0) {
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092,
+                   "Ignoring stale deletion request for se_sess %p / sess %p"
+                   " for port %8phC, req_gen %d, sess_gen %d\n",
+                   sess->se_sess, sess, sess->port_name, max_gen,
+                   sess->generation);
                return;
        }
 
@@ -808,7 +927,6 @@ void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport)
 
        sess->local = 1;
        qlt_schedule_sess_for_deletion(sess, false);
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
 static inline int test_tgt_sess_count(struct qla_tgt *tgt)
@@ -1175,6 +1293,70 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha,
            FCP_TMF_CMPL, true);
 }
 
+static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag)
+{
+       struct qla_tgt_sess_op *op;
+       struct qla_tgt_cmd *cmd;
+
+       spin_lock(&vha->cmd_list_lock);
+
+       list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) {
+               if (tag == op->atio.u.isp24.exchange_addr) {
+                       op->aborted = true;
+                       spin_unlock(&vha->cmd_list_lock);
+                       return 1;
+               }
+       }
+
+       list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
+               if (tag == cmd->atio.u.isp24.exchange_addr) {
+                       cmd->state = QLA_TGT_STATE_ABORTED;
+                       spin_unlock(&vha->cmd_list_lock);
+                       return 1;
+               }
+       }
+
+       spin_unlock(&vha->cmd_list_lock);
+       return 0;
+}
+
+/* drop cmds for the given lun
+ * XXX only looks for cmds on the port through which lun reset was recieved
+ * XXX does not go through the list of other port (which may have cmds
+ *     for the same lun)
+ */
+static void abort_cmds_for_lun(struct scsi_qla_host *vha,
+                               uint32_t lun, uint8_t *s_id)
+{
+       struct qla_tgt_sess_op *op;
+       struct qla_tgt_cmd *cmd;
+       uint32_t key;
+
+       key = sid_to_key(s_id);
+       spin_lock(&vha->cmd_list_lock);
+       list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) {
+               uint32_t op_key;
+               uint32_t op_lun;
+
+               op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id);
+               op_lun = scsilun_to_int(
+                       (struct scsi_lun *)&op->atio.u.isp24.fcp_cmnd.lun);
+               if (op_key == key && op_lun == lun)
+                       op->aborted = true;
+       }
+       list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
+               uint32_t cmd_key;
+               uint32_t cmd_lun;
+
+               cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
+               cmd_lun = scsilun_to_int(
+                       (struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun);
+               if (cmd_key == key && cmd_lun == lun)
+                       cmd->state = QLA_TGT_STATE_ABORTED;
+       }
+       spin_unlock(&vha->cmd_list_lock);
+}
+
 /* ha->hardware_lock supposed to be held on entry */
 static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
        struct abts_recv_from_24xx *abts, struct qla_tgt_sess *sess)
@@ -1199,8 +1381,19 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
        }
        spin_unlock(&se_sess->sess_cmd_lock);
 
-       if (!found_lun)
-               return -ENOENT;
+       /* cmd not in LIO lists, look in qla list */
+       if (!found_lun) {
+               if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) {
+                       /* send TASK_ABORT response immediately */
+                       qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_CMPL, false);
+                       return 0;
+               } else {
+                       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf081,
+                           "unable to find cmd in driver or LIO for tag 0x%x\n",
+                           abts->exchange_addr_to_abort);
+                       return -ENOENT;
+               }
+       }
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f,
            "qla_target(%d): task abort (tag=%d)\n",
@@ -1284,6 +1477,11 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
                return;
        }
 
+       if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+               qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false);
+               return;
+       }
+
        rc = __qlt_24xx_handle_abts(vha, abts, sess);
        if (rc != 0) {
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf054,
@@ -1726,20 +1924,6 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd,
        struct qla_hw_data *ha = vha->hw;
        struct se_cmd *se_cmd = &cmd->se_cmd;
 
-       if (unlikely(cmd->aborted)) {
-               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
-                      "qla_target(%d): terminating exchange for aborted cmd=%p (se_cmd=%p, tag=%lld)",
-                      vha->vp_idx, cmd, se_cmd, se_cmd->tag);
-
-               cmd->state = QLA_TGT_STATE_ABORTED;
-               cmd->cmd_flags |= BIT_6;
-
-               qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
-
-               /* !! At this point cmd could be already freed !! */
-               return QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED;
-       }
-
        prm->cmd = cmd;
        prm->tgt = tgt;
        prm->rq_result = scsi_status;
@@ -2301,6 +2485,19 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
        unsigned long flags = 0;
        int res;
 
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       if (cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+               cmd->state = QLA_TGT_STATE_PROCESSED;
+               if (cmd->sess->logout_completed)
+                       /* no need to terminate. FW already freed exchange. */
+                       qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
+               else
+                       qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               return 0;
+       }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
        memset(&prm, 0, sizeof(prm));
        qlt_check_srr_debug(cmd, &xmit_type);
 
@@ -2313,9 +2510,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
        res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status,
            &full_req_cnt);
        if (unlikely(res != 0)) {
-               if (res == QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED)
-                       return 0;
-
                return res;
        }
 
@@ -2345,9 +2539,10 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
                res = qlt_build_ctio_crc2_pkt(&prm, vha);
        else
                res = qlt_24xx_build_ctio_pkt(&prm, vha);
-       if (unlikely(res != 0))
+       if (unlikely(res != 0)) {
+               vha->req->cnt += full_req_cnt;
                goto out_unmap_unlock;
-
+       }
 
        pkt = (struct ctio7_to_24xx *)prm.pkt;
 
@@ -2461,7 +2656,8 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
-       if (qla2x00_reset_active(vha) || cmd->reset_count != ha->chip_reset) {
+       if (qla2x00_reset_active(vha) || (cmd->reset_count != ha->chip_reset) ||
+           (cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)) {
                /*
                 * Either a chip reset is active or this request was from
                 * previous life, just abort the processing.
@@ -2485,8 +2681,11 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
        else
                res = qlt_24xx_build_ctio_pkt(&prm, vha);
 
-       if (unlikely(res != 0))
+       if (unlikely(res != 0)) {
+               vha->req->cnt += prm.req_cnt;
                goto out_unlock_free_unmap;
+       }
+
        pkt = (struct ctio7_to_24xx *)prm.pkt;
        pkt->u.status0.flags |= __constant_cpu_to_le16(CTIO7_FLAGS_DATA_OUT |
            CTIO7_FLAGS_STATUS_MODE_0);
@@ -2649,6 +2848,89 @@ out:
 }
 
 
+/* If hardware_lock held on entry, might drop it, then reaquire */
+/* This function sends the appropriate CTIO to ISP 2xxx or 24xx */
+static int __qlt_send_term_imm_notif(struct scsi_qla_host *vha,
+       struct imm_ntfy_from_isp *ntfy)
+{
+       struct nack_to_isp *nack;
+       struct qla_hw_data *ha = vha->hw;
+       request_t *pkt;
+       int ret = 0;
+
+       ql_dbg(ql_dbg_tgt_tmr, vha, 0xe01c,
+           "Sending TERM ELS CTIO (ha=%p)\n", ha);
+
+       pkt = (request_t *)qla2x00_alloc_iocbs_ready(vha, NULL);
+       if (pkt == NULL) {
+               ql_dbg(ql_dbg_tgt, vha, 0xe080,
+                   "qla_target(%d): %s failed: unable to allocate "
+                   "request packet\n", vha->vp_idx, __func__);
+               return -ENOMEM;
+       }
+
+       pkt->entry_type = NOTIFY_ACK_TYPE;
+       pkt->entry_count = 1;
+       pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
+
+       nack = (struct nack_to_isp *)pkt;
+       nack->ox_id = ntfy->ox_id;
+
+       nack->u.isp24.nport_handle = ntfy->u.isp24.nport_handle;
+       if (le16_to_cpu(ntfy->u.isp24.status) == IMM_NTFY_ELS) {
+               nack->u.isp24.flags = ntfy->u.isp24.flags &
+                       __constant_cpu_to_le32(NOTIFY24XX_FLAGS_PUREX_IOCB);
+       }
+
+       /* terminate */
+       nack->u.isp24.flags |=
+               __constant_cpu_to_le16(NOTIFY_ACK_FLAGS_TERMINATE);
+
+       nack->u.isp24.srr_rx_id = ntfy->u.isp24.srr_rx_id;
+       nack->u.isp24.status = ntfy->u.isp24.status;
+       nack->u.isp24.status_subcode = ntfy->u.isp24.status_subcode;
+       nack->u.isp24.fw_handle = ntfy->u.isp24.fw_handle;
+       nack->u.isp24.exchange_address = ntfy->u.isp24.exchange_address;
+       nack->u.isp24.srr_rel_offs = ntfy->u.isp24.srr_rel_offs;
+       nack->u.isp24.srr_ui = ntfy->u.isp24.srr_ui;
+       nack->u.isp24.vp_index = ntfy->u.isp24.vp_index;
+
+       qla2x00_start_iocbs(vha, vha->req);
+       return ret;
+}
+
+static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
+       struct imm_ntfy_from_isp *imm, int ha_locked)
+{
+       unsigned long flags = 0;
+       int rc;
+
+       if (qlt_issue_marker(vha, ha_locked) < 0)
+               return;
+
+       if (ha_locked) {
+               rc = __qlt_send_term_imm_notif(vha, imm);
+
+#if 0  /* Todo  */
+               if (rc == -ENOMEM)
+                       qlt_alloc_qfull_cmd(vha, imm, 0, 0);
+#endif
+               goto done;
+       }
+
+       spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+       rc = __qlt_send_term_imm_notif(vha, imm);
+
+#if 0  /* Todo */
+       if (rc == -ENOMEM)
+               qlt_alloc_qfull_cmd(vha, imm, 0, 0);
+#endif
+
+done:
+       if (!ha_locked)
+               spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+}
+
 /* If hardware_lock held on entry, might drop it, then reaquire */
 /* This function sends the appropriate CTIO to ISP 2xxx or 24xx */
 static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
@@ -2715,7 +2997,7 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
 static void qlt_send_term_exchange(struct scsi_qla_host *vha,
        struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked)
 {
-       unsigned long flags;
+       unsigned long flags = 0;
        int rc;
 
        if (qlt_issue_marker(vha, ha_locked) < 0)
@@ -2731,17 +3013,18 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
        rc = __qlt_send_term_exchange(vha, cmd, atio);
        if (rc == -ENOMEM)
                qlt_alloc_qfull_cmd(vha, atio, 0, 0);
-       spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
 
 done:
        if (cmd && ((cmd->state != QLA_TGT_STATE_ABORTED) ||
            !cmd->cmd_sent_to_fw)) {
-               if (!ha_locked && !in_interrupt())
-                       msleep(250); /* just in case */
-
-               qlt_unmap_sg(vha, cmd);
+               if (cmd->sg_mapped)
+                       qlt_unmap_sg(vha, cmd);
                vha->hw->tgt.tgt_ops->free_cmd(cmd);
        }
+
+       if (!ha_locked)
+               spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+
        return;
 }
 
@@ -2792,6 +3075,24 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
 
 }
 
+void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
+{
+       struct qla_tgt *tgt = cmd->tgt;
+       struct scsi_qla_host *vha = tgt->vha;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+
+       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
+           "qla_target(%d): terminating exchange for aborted cmd=%p "
+           "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
+           se_cmd->tag);
+
+       cmd->state = QLA_TGT_STATE_ABORTED;
+       cmd->cmd_flags |= BIT_6;
+
+       qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
+}
+EXPORT_SYMBOL(qlt_abort_cmd);
+
 void qlt_free_cmd(struct qla_tgt_cmd *cmd)
 {
        struct qla_tgt_sess *sess = cmd->sess;
@@ -3015,7 +3316,7 @@ qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
                dump_stack();
        }
 
-       cmd->cmd_flags |= BIT_12;
+       cmd->cmd_flags |= BIT_17;
        ha->tgt.tgt_ops->free_cmd(cmd);
 }
 
@@ -3177,7 +3478,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
 skip_term:
 
        if (cmd->state == QLA_TGT_STATE_PROCESSED) {
-               ;
+               cmd->cmd_flags |= BIT_12;
        } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) {
                int rx_status = 0;
 
@@ -3191,9 +3492,11 @@ skip_term:
                ha->tgt.tgt_ops->handle_data(cmd);
                return;
        } else if (cmd->state == QLA_TGT_STATE_ABORTED) {
+               cmd->cmd_flags |= BIT_18;
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e,
                  "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag);
        } else {
+               cmd->cmd_flags |= BIT_19;
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c,
                    "qla_target(%d): A command in state (%d) should "
                    "not return a CTIO complete\n", vha->vp_idx, cmd->state);
@@ -3205,7 +3508,6 @@ skip_term:
                dump_stack();
        }
 
-
        ha->tgt.tgt_ops->free_cmd(cmd);
 }
 
@@ -3263,6 +3565,13 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
        if (tgt->tgt_stop)
                goto out_term;
 
+       if (cmd->state == QLA_TGT_STATE_ABORTED) {
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082,
+                   "cmd with tag %u is aborted\n",
+                   cmd->atio.u.isp24.exchange_addr);
+               goto out_term;
+       }
+
        cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
        cmd->se_cmd.tag = atio->u.isp24.exchange_addr;
        cmd->unpacked_lun = scsilun_to_int(
@@ -3316,6 +3625,12 @@ out_term:
 static void qlt_do_work(struct work_struct *work)
 {
        struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+       scsi_qla_host_t *vha = cmd->vha;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vha->cmd_list_lock, flags);
+       list_del(&cmd->cmd_list);
+       spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
 
        __qlt_do_work(cmd);
 }
@@ -3345,6 +3660,11 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
        cmd->loop_id = sess->loop_id;
        cmd->conf_compl_supported = sess->conf_compl_supported;
 
+       cmd->cmd_flags = 0;
+       cmd->jiffies_at_alloc = get_jiffies_64();
+
+       cmd->reset_count = vha->hw->chip_reset;
+
        return cmd;
 }
 
@@ -3362,14 +3682,25 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
        unsigned long flags;
        uint8_t *s_id = op->atio.u.isp24.fcp_hdr.s_id;
 
+       spin_lock_irqsave(&vha->cmd_list_lock, flags);
+       list_del(&op->cmd_list);
+       spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
+
+       if (op->aborted) {
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf083,
+                   "sess_op with tag %u is aborted\n",
+                   op->atio.u.isp24.exchange_addr);
+               goto out_term;
+       }
+
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022,
-               "qla_target(%d): Unable to find wwn login"
-               " (s_id %x:%x:%x), trying to create it manually\n",
-               vha->vp_idx, s_id[0], s_id[1], s_id[2]);
+           "qla_target(%d): Unable to find wwn login"
+           " (s_id %x:%x:%x), trying to create it manually\n",
+           vha->vp_idx, s_id[0], s_id[1], s_id[2]);
 
        if (op->atio.u.raw.entry_count > 1) {
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023,
-                       "Dropping multy entry atio %p\n", &op->atio);
+                   "Dropping multy entry atio %p\n", &op->atio);
                goto out_term;
        }
 
@@ -3434,10 +3765,25 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
 
                memcpy(&op->atio, atio, sizeof(*atio));
                op->vha = vha;
+
+               spin_lock(&vha->cmd_list_lock);
+               list_add_tail(&op->cmd_list, &vha->qla_sess_op_cmd_list);
+               spin_unlock(&vha->cmd_list_lock);
+
                INIT_WORK(&op->work, qlt_create_sess_from_atio);
                queue_work(qla_tgt_wq, &op->work);
                return 0;
        }
+
+       /* Another WWN used to have our s_id. Our PLOGI scheduled its
+        * session deletion, but it's still in sess_del_work wq */
+       if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+               ql_dbg(ql_dbg_io, vha, 0x3061,
+                   "New command while old session %p is being deleted\n",
+                   sess);
+               return -EFAULT;
+       }
+
        /*
         * Do kref_get() before returning + dropping qla_hw_data->hardware_lock.
         */
@@ -3451,13 +3797,13 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
                return -ENOMEM;
        }
 
-       cmd->cmd_flags = 0;
-       cmd->jiffies_at_alloc = get_jiffies_64();
-
-       cmd->reset_count = vha->hw->chip_reset;
-
        cmd->cmd_in_wq = 1;
        cmd->cmd_flags |= BIT_0;
+
+       spin_lock(&vha->cmd_list_lock);
+       list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list);
+       spin_unlock(&vha->cmd_list_lock);
+
        INIT_WORK(&cmd->work, qlt_do_work);
        queue_work(qla_tgt_wq, &cmd->work);
        return 0;
@@ -3471,6 +3817,7 @@ static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
        struct scsi_qla_host *vha = sess->vha;
        struct qla_hw_data *ha = vha->hw;
        struct qla_tgt_mgmt_cmd *mcmd;
+       struct atio_from_isp *a = (struct atio_from_isp *)iocb;
        int res;
        uint8_t tmr_func;
 
@@ -3511,6 +3858,7 @@ static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
                ql_dbg(ql_dbg_tgt_tmr, vha, 0x10002,
                    "qla_target(%d): LUN_RESET received\n", sess->vha->vp_idx);
                tmr_func = TMR_LUN_RESET;
+               abort_cmds_for_lun(vha, lun, a->u.isp24.fcp_hdr.s_id);
                break;
 
        case QLA_TGT_CLEAR_TS:
@@ -3599,6 +3947,9 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb)
                    sizeof(struct atio_from_isp));
        }
 
+       if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)
+               return -EFAULT;
+
        return qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0);
 }
 
@@ -3664,22 +4015,280 @@ static int qlt_abort_task(struct scsi_qla_host *vha,
        return __qlt_abort_task(vha, iocb, sess);
 }
 
+void qlt_logo_completion_handler(fc_port_t *fcport, int rc)
+{
+       if (fcport->tgt_session) {
+               if (rc != MBS_COMMAND_COMPLETE) {
+                       ql_dbg(ql_dbg_tgt_mgt, fcport->vha, 0xf093,
+                               "%s: se_sess %p / sess %p from"
+                               " port %8phC loop_id %#04x s_id %02x:%02x:%02x"
+                               " LOGO failed: %#x\n",
+                               __func__,
+                               fcport->tgt_session->se_sess,
+                               fcport->tgt_session,
+                               fcport->port_name, fcport->loop_id,
+                               fcport->d_id.b.domain, fcport->d_id.b.area,
+                               fcport->d_id.b.al_pa, rc);
+               }
+
+               fcport->tgt_session->logout_completed = 1;
+       }
+}
+
+static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
+    struct imm_ntfy_from_isp *b)
+{
+       struct imm_ntfy_from_isp tmp;
+       memcpy(&tmp, a, sizeof(struct imm_ntfy_from_isp));
+       memcpy(a, b, sizeof(struct imm_ntfy_from_isp));
+       memcpy(b, &tmp, sizeof(struct imm_ntfy_from_isp));
+}
+
+/*
+* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list)
+*
+* Schedules sessions with matching port_id/loop_id but different wwn for
+* deletion. Returns existing session with matching wwn if present.
+* Null otherwise.
+*/
+static struct qla_tgt_sess *
+qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
+    port_id_t port_id, uint16_t loop_id)
+{
+       struct qla_tgt_sess *sess = NULL, *other_sess;
+       uint64_t other_wwn;
+
+       list_for_each_entry(other_sess, &tgt->sess_list, sess_list_entry) {
+
+               other_wwn = wwn_to_u64(other_sess->port_name);
+
+               if (wwn == other_wwn) {
+                       WARN_ON(sess);
+                       sess = other_sess;
+                       continue;
+               }
+
+               /* find other sess with nport_id collision */
+               if (port_id.b24 == other_sess->s_id.b24) {
+                       if (loop_id != other_sess->loop_id) {
+                               ql_dbg(ql_dbg_tgt_tmr, tgt->vha, 0x1000c,
+                                   "Invalidating sess %p loop_id %d wwn %llx.\n",
+                                   other_sess, other_sess->loop_id, other_wwn);
+
+                               /*
+                                * logout_on_delete is set by default, but another
+                                * session that has the same s_id/loop_id combo
+                                * might have cleared it when requested this session
+                                * deletion, so don't touch it
+                                */
+                               qlt_schedule_sess_for_deletion(other_sess, true);
+                       } else {
+                               /*
+                                * Another wwn used to have our s_id/loop_id
+                                * combo - kill the session, but don't log out
+                                */
+                               sess->logout_on_delete = 0;
+                               qlt_schedule_sess_for_deletion(other_sess,
+                                   true);
+                       }
+                       continue;
+               }
+
+               /* find other sess with nport handle collision */
+               if (loop_id == other_sess->loop_id) {
+                       ql_dbg(ql_dbg_tgt_tmr, tgt->vha, 0x1000d,
+                              "Invalidating sess %p loop_id %d wwn %llx.\n",
+                              other_sess, other_sess->loop_id, other_wwn);
+
+                       /* Same loop_id but different s_id
+                        * Ok to kill and logout */
+                       qlt_schedule_sess_for_deletion(other_sess, true);
+               }
+       }
+
+       return sess;
+}
+
+/* Abort any commands for this s_id waiting on qla_tgt_wq workqueue */
+static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id)
+{
+       struct qla_tgt_sess_op *op;
+       struct qla_tgt_cmd *cmd;
+       uint32_t key;
+       int count = 0;
+
+       key = (((u32)s_id->b.domain << 16) |
+              ((u32)s_id->b.area   <<  8) |
+              ((u32)s_id->b.al_pa));
+
+       spin_lock(&vha->cmd_list_lock);
+       list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) {
+               uint32_t op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id);
+               if (op_key == key) {
+                       op->aborted = true;
+                       count++;
+               }
+       }
+       list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
+               uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
+               if (cmd_key == key) {
+                       cmd->state = QLA_TGT_STATE_ABORTED;
+                       count++;
+               }
+       }
+       spin_unlock(&vha->cmd_list_lock);
+
+       return count;
+}
+
 /*
  * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
  */
 static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
        struct imm_ntfy_from_isp *iocb)
 {
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
+       struct qla_hw_data *ha = vha->hw;
+       struct qla_tgt_sess *sess = NULL;
+       uint64_t wwn;
+       port_id_t port_id;
+       uint16_t loop_id;
+       uint16_t wd3_lo;
        int res = 0;
 
+       wwn = wwn_to_u64(iocb->u.isp24.port_name);
+
+       port_id.b.domain = iocb->u.isp24.port_id[2];
+       port_id.b.area   = iocb->u.isp24.port_id[1];
+       port_id.b.al_pa  = iocb->u.isp24.port_id[0];
+       port_id.b.rsvd_1 = 0;
+
+       loop_id = le16_to_cpu(iocb->u.isp24.nport_handle);
+
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf026,
            "qla_target(%d): Port ID: 0x%3phC ELS opcode: 0x%02x\n",
            vha->vp_idx, iocb->u.isp24.port_id, iocb->u.isp24.status_subcode);
 
+       /* res = 1 means ack at the end of thread
+        * res = 0 means ack async/later.
+        */
        switch (iocb->u.isp24.status_subcode) {
        case ELS_PLOGI:
-       case ELS_FLOGI:
+
+               /* Mark all stale commands in qla_tgt_wq for deletion */
+               abort_cmds_for_s_id(vha, &port_id);
+
+               if (wwn)
+                       sess = qlt_find_sess_invalidate_other(tgt, wwn,
+                           port_id, loop_id);
+
+               if (!sess || IS_SW_RESV_ADDR(sess->s_id)) {
+                       res = 1;
+                       break;
+               }
+
+               if (sess->plogi_ack_needed) {
+                       /*
+                        * Initiator sent another PLOGI before last PLOGI could
+                        * finish. Swap plogi iocbs and terminate old one
+                        * without acking, new one will get acked when session
+                        * deletion completes.
+                        */
+                       ql_log(ql_log_warn, sess->vha, 0xf094,
+                           "sess %p received double plogi.\n", sess);
+
+                       qlt_swap_imm_ntfy_iocb(iocb, &sess->tm_iocb);
+
+                       qlt_send_term_imm_notif(vha, iocb, 1);
+
+                       res = 0;
+                       break;
+               }
+
+               res = 0;
+
+               /*
+                * Save immediate Notif IOCB for Ack when sess is done
+                * and being deleted.
+                */
+               memcpy(&sess->tm_iocb, iocb, sizeof(sess->tm_iocb));
+               sess->plogi_ack_needed  = 1;
+
+                /*
+                 * Under normal circumstances we want to release nport handle
+                 * during LOGO process to avoid nport handle leaks inside FW.
+                 * The exception is when LOGO is done while another PLOGI with
+                 * the same nport handle is waiting as might be the case here.
+                 * Note: there is always a possibily of a race where session
+                 * deletion has already started for other reasons (e.g. ACL
+                 * removal) and now PLOGI arrives:
+                 * 1. if PLOGI arrived in FW after nport handle has been freed,
+                 *    FW must have assigned this PLOGI a new/same handle and we
+                 *    can proceed ACK'ing it as usual when session deletion
+                 *    completes.
+                 * 2. if PLOGI arrived in FW before LOGO with LCF_FREE_NPORT
+                 *    bit reached it, the handle has now been released. We'll
+                 *    get an error when we ACK this PLOGI. Nothing will be sent
+                 *    back to initiator. Initiator should eventually retry
+                 *    PLOGI and situation will correct itself.
+                 */
+               sess->keep_nport_handle = ((sess->loop_id == loop_id) &&
+                                          (sess->s_id.b24 == port_id.b24));
+               qlt_schedule_sess_for_deletion(sess, true);
+               break;
+
        case ELS_PRLI:
+               wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo);
+
+               if (wwn)
+                       sess = qlt_find_sess_invalidate_other(tgt, wwn, port_id,
+                           loop_id);
+
+               if (sess != NULL) {
+                       if (sess->deleted) {
+                               /*
+                                * Impatient initiator sent PRLI before last
+                                * PLOGI could finish. Will force him to re-try,
+                                * while last one finishes.
+                                */
+                               ql_log(ql_log_warn, sess->vha, 0xf095,
+                                   "sess %p PRLI received, before plogi ack.\n",
+                                   sess);
+                               qlt_send_term_imm_notif(vha, iocb, 1);
+                               res = 0;
+                               break;
+                       }
+
+                       /*
+                        * This shouldn't happen under normal circumstances,
+                        * since we have deleted the old session during PLOGI
+                        */
+                       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf096,
+                           "PRLI (loop_id %#04x) for existing sess %p (loop_id %#04x)\n",
+                           sess->loop_id, sess, iocb->u.isp24.nport_handle);
+
+                       sess->local = 0;
+                       sess->loop_id = loop_id;
+                       sess->s_id = port_id;
+
+                       if (wd3_lo & BIT_7)
+                               sess->conf_compl_supported = 1;
+
+               }
+               res = 1; /* send notify ack */
+
+               /* Make session global (not used in fabric mode) */
+               if (ha->current_topology != ISP_CFG_F) {
+                       set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+                       set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
+                       qla2xxx_wake_dpc(vha);
+               } else {
+                       /* todo: else - create sess here. */
+                       res = 1; /* send notify ack */
+               }
+
+               break;
+
        case ELS_LOGO:
        case ELS_PRLO:
                res = qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS);
@@ -3697,6 +4306,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
                break;
        }
 
+       case ELS_FLOGI: /* should never happen */
        default:
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf061,
                    "qla_target(%d): Unsupported ELS command %x "
@@ -5012,6 +5622,11 @@ static void qlt_abort_work(struct qla_tgt *tgt,
                if (!sess)
                        goto out_term;
        } else {
+               if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+                       sess = NULL;
+                       goto out_term;
+               }
+
                kref_get(&sess->se_sess->sess_kref);
        }
 
@@ -5066,6 +5681,11 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
                if (!sess)
                        goto out_term;
        } else {
+               if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+                       sess = NULL;
+                       goto out_term;
+               }
+
                kref_get(&sess->se_sess->sess_kref);
        }
 
@@ -5552,6 +6172,7 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
 
        /* Adjust ring index */
        WRT_REG_DWORD(ISP_ATIO_Q_OUT(vha), ha->tgt.atio_ring_index);
+       RD_REG_DWORD_RELAXED(ISP_ATIO_Q_OUT(vha));
 }
 
 void
@@ -5793,7 +6414,7 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha)
        if (!QLA_TGT_MODE_ENABLED())
                return;
 
-       if  (ha->mqenable || IS_QLA83XX(ha)) {
+       if  (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
                ISP_ATIO_Q_IN(base_vha) = &ha->mqiobase->isp25mq.atio_q_in;
                ISP_ATIO_Q_OUT(base_vha) = &ha->mqiobase->isp25mq.atio_q_out;
        } else {
index 985d76dd706b71b3da1b3685169a21c24af90fa0..bca584ae45b7eccc3da35a11c9583c324524a802 100644 (file)
@@ -167,7 +167,24 @@ struct imm_ntfy_from_isp {
                        uint32_t srr_rel_offs;
                        uint16_t srr_ui;
                        uint16_t srr_ox_id;
-                       uint8_t  reserved_4[19];
+                       union {
+                               struct {
+                                       uint8_t node_name[8];
+                               } plogi; /* PLOGI/ADISC/PDISC */
+                               struct {
+                                       /* PRLI word 3 bit 0-15 */
+                                       uint16_t wd3_lo;
+                                       uint8_t resv0[6];
+                               } prli;
+                               struct {
+                                       uint8_t port_id[3];
+                                       uint8_t resv1;
+                                       uint16_t nport_handle;
+                                       uint16_t resv2;
+                               } req_els;
+                       } u;
+                       uint8_t port_name[8];
+                       uint8_t resv3[3];
                        uint8_t  vp_index;
                        uint32_t reserved_5;
                        uint8_t  port_id[3];
@@ -234,6 +251,7 @@ struct nack_to_isp {
        uint8_t  reserved[2];
        uint16_t ox_id;
 } __packed;
+#define NOTIFY_ACK_FLAGS_TERMINATE     BIT_3
 #define NOTIFY_ACK_SRR_FLAGS_ACCEPT    0
 #define NOTIFY_ACK_SRR_FLAGS_REJECT    1
 
@@ -790,13 +808,6 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
 #define        FC_TM_REJECT                4
 #define FC_TM_FAILED                5
 
-/*
- * Error code of qlt_pre_xmit_response() meaning that cmd's exchange was
- * terminated, so no more actions is needed and success should be returned
- * to target.
- */
-#define QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED      0x1717
-
 #if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G)
 #define pci_dma_lo32(a) (a & 0xffffffff)
 #define pci_dma_hi32(a) ((((a) >> 16)>>16) & 0xffffffff)
@@ -874,6 +885,15 @@ struct qla_tgt_sess_op {
        struct scsi_qla_host *vha;
        struct atio_from_isp atio;
        struct work_struct work;
+       struct list_head cmd_list;
+       bool aborted;
+};
+
+enum qla_sess_deletion {
+       QLA_SESS_DELETION_NONE          = 0,
+       QLA_SESS_DELETION_PENDING       = 1, /* hopefully we can get rid of
+                                             * this one */
+       QLA_SESS_DELETION_IN_PROGRESS   = 2,
 };
 
 /*
@@ -884,8 +904,15 @@ struct qla_tgt_sess {
        port_id_t s_id;
 
        unsigned int conf_compl_supported:1;
-       unsigned int deleted:1;
+       unsigned int deleted:2;
        unsigned int local:1;
+       unsigned int logout_on_delete:1;
+       unsigned int plogi_ack_needed:1;
+       unsigned int keep_nport_handle:1;
+
+       unsigned char logout_completed;
+
+       int generation;
 
        struct se_session *se_sess;
        struct scsi_qla_host *vha;
@@ -897,6 +924,10 @@ struct qla_tgt_sess {
 
        uint8_t port_name[WWN_SIZE];
        struct work_struct free_work;
+
+       union {
+               struct imm_ntfy_from_isp tm_iocb;
+       };
 };
 
 struct qla_tgt_cmd {
@@ -912,7 +943,6 @@ struct qla_tgt_cmd {
        unsigned int conf_compl_supported:1;
        unsigned int sg_mapped:1;
        unsigned int free_sg:1;
-       unsigned int aborted:1; /* Needed in case of SRR */
        unsigned int write_data_transferred:1;
        unsigned int ctx_dsd_alloced:1;
        unsigned int q_full:1;
@@ -961,6 +991,9 @@ struct qla_tgt_cmd {
         * BIT_14 - Back end data received/sent.
         * BIT_15 - SRR prepare ctio
         * BIT_16 - complete free
+        * BIT_17 - flush - qlt_abort_cmd_on_host_reset
+        * BIT_18 - completion w/abort status
+        * BIT_19 - completion w/unknown status
         */
        uint32_t cmd_flags;
 };
@@ -1026,6 +1059,10 @@ struct qla_tgt_srr_ctio {
        struct qla_tgt_cmd *cmd;
 };
 
+/* Check for Switch reserved address */
+#define IS_SW_RESV_ADDR(_s_id) \
+       ((_s_id.b.domain == 0xff) && (_s_id.b.area == 0xfc))
+
 #define QLA_TGT_XMIT_DATA              1
 #define QLA_TGT_XMIT_STATUS            2
 #define QLA_TGT_XMIT_ALL               (QLA_TGT_XMIT_STATUS|QLA_TGT_XMIT_DATA)
@@ -1043,7 +1080,7 @@ extern int qlt_lport_register(void *, u64, u64, u64,
 extern void qlt_lport_deregister(struct scsi_qla_host *);
 extern void qlt_unreg_sess(struct qla_tgt_sess *);
 extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *);
-extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *);
+extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *, int);
 extern int __init qlt_init(void);
 extern void qlt_exit(void);
 extern void qlt_update_vp_map(struct scsi_qla_host *, int);
@@ -1073,12 +1110,23 @@ static inline void qla_reverse_ini_mode(struct scsi_qla_host *ha)
                ha->host->active_mode |= MODE_INITIATOR;
 }
 
+static inline uint32_t sid_to_key(const uint8_t *s_id)
+{
+       uint32_t key;
+
+       key = (((unsigned long)s_id[0] << 16) |
+              ((unsigned long)s_id[1] << 8) |
+              (unsigned long)s_id[2]);
+       return key;
+}
+
 /*
  * Exported symbols from qla_target.c LLD logic used by qla2xxx code..
  */
 extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *);
 extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
 extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
+extern void qlt_abort_cmd(struct qla_tgt_cmd *);
 extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
 extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
 extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
@@ -1109,5 +1157,7 @@ extern void qlt_stop_phase2(struct qla_tgt *);
 extern irqreturn_t qla83xx_msix_atio_q(int, void *);
 extern void qlt_83xx_iospace_config(struct qla_hw_data *);
 extern int qlt_free_qfull_cmds(struct scsi_qla_host *);
+extern void qlt_logo_completion_handler(fc_port_t *, int);
+extern void qlt_do_generation_tick(struct scsi_qla_host *, int *);
 
 #endif /* __QLA_TARGET_H */
index d9a8c6084346759778c5cd8506c42d4ead19e2cc..9224a06646e6af420139ae29cba4802cf2663637 100644 (file)
@@ -374,7 +374,7 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
 {
        struct qla_tgt_cmd *cmd = container_of(se_cmd,
                                struct qla_tgt_cmd, se_cmd);
-
+       cmd->cmd_flags |= BIT_3;
        cmd->bufflen = se_cmd->data_length;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
 
@@ -405,7 +405,7 @@ static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd)
            se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) {
                spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
                wait_for_completion_timeout(&se_cmd->t_transport_stop_comp,
-                                               3000);
+                                           3 * HZ);
                return 0;
        }
        spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
@@ -541,12 +541,10 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
        cmd->cmd_flags |= BIT_4;
        cmd->bufflen = se_cmd->data_length;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
-       cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED);
 
        cmd->sg_cnt = se_cmd->t_data_nents;
        cmd->sg = se_cmd->t_data_sg;
        cmd->offset = 0;
-       cmd->cmd_flags |= BIT_3;
 
        cmd->prot_sg_cnt = se_cmd->t_prot_nents;
        cmd->prot_sg = se_cmd->t_prot_sg;
@@ -571,7 +569,6 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
        cmd->sg_cnt = 0;
        cmd->offset = 0;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
-       cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED);
        if (cmd->cmd_flags &  BIT_5) {
                pr_crit("Bit_5 already set for cmd = %p.\n", cmd);
                dump_stack();
@@ -636,14 +633,7 @@ static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
 {
        struct qla_tgt_cmd *cmd = container_of(se_cmd,
                                struct qla_tgt_cmd, se_cmd);
-       struct scsi_qla_host *vha = cmd->vha;
-       struct qla_hw_data *ha = vha->hw;
-
-       if (!cmd->sg_mapped)
-               return;
-
-       pci_unmap_sg(ha->pdev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction);
-       cmd->sg_mapped = 0;
+       qlt_abort_cmd(cmd);
 }
 
 static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
@@ -1149,9 +1139,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
                return NULL;
        }
 
-       key = (((unsigned long)s_id[0] << 16) |
-              ((unsigned long)s_id[1] << 8) |
-              (unsigned long)s_id[2]);
+       key = sid_to_key(s_id);
        pr_debug("find_sess_by_s_id: 0x%06x\n", key);
 
        se_nacl = btree_lookup32(&lport->lport_fcport_map, key);
@@ -1186,9 +1174,7 @@ static void tcm_qla2xxx_set_sess_by_s_id(
        void *slot;
        int rc;
 
-       key = (((unsigned long)s_id[0] << 16) |
-              ((unsigned long)s_id[1] << 8) |
-              (unsigned long)s_id[2]);
+       key = sid_to_key(s_id);
        pr_debug("set_sess_by_s_id: %06x\n", key);
 
        slot = btree_lookup32(&lport->lport_fcport_map, key);
@@ -1544,6 +1530,10 @@ static void tcm_qla2xxx_update_sess(struct qla_tgt_sess *sess, port_id_t s_id,
        }
 
        sess->conf_compl_supported = conf_compl_supported;
+
+       /* Reset logout parameters to default */
+       sess->logout_on_delete = 1;
+       sess->keep_nport_handle = 0;
 }
 
 /*
index 106884a5444e1cb6f61057c29f813c4d713760fa..cfadccef045c5f91d9efb5f575c98d1d9c68b090 100644 (file)
@@ -944,7 +944,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
                            scmd->sdb.length);
                scmd->sdb.table.sgl = &ses->sense_sgl;
                scmd->sc_data_direction = DMA_FROM_DEVICE;
-               scmd->sdb.table.nents = 1;
+               scmd->sdb.table.nents = scmd->sdb.table.orig_nents = 1;
                scmd->cmnd[0] = REQUEST_SENSE;
                scmd->cmnd[4] = scmd->sdb.length;
                scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
index b1a263137a23391a1e19c2589f35fdaf2c4f514f..448ebdaa3d694758dd899b1c06ce379d0676898a 100644 (file)
@@ -583,7 +583,7 @@ static struct scatterlist *scsi_sg_alloc(unsigned int nents, gfp_t gfp_mask)
 
 static void scsi_free_sgtable(struct scsi_data_buffer *sdb, bool mq)
 {
-       if (mq && sdb->table.nents <= SCSI_MAX_SG_SEGMENTS)
+       if (mq && sdb->table.orig_nents <= SCSI_MAX_SG_SEGMENTS)
                return;
        __sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, mq, scsi_sg_free);
 }
@@ -597,8 +597,8 @@ static int scsi_alloc_sgtable(struct scsi_data_buffer *sdb, int nents, bool mq)
 
        if (mq) {
                if (nents <= SCSI_MAX_SG_SEGMENTS) {
-                       sdb->table.nents = nents;
-                       sg_init_table(sdb->table.sgl, sdb->table.nents);
+                       sdb->table.nents = sdb->table.orig_nents = nents;
+                       sg_init_table(sdb->table.sgl, nents);
                        return 0;
                }
                first_chunk = sdb->table.sgl;
index 3b2fcb4fada0491c4500b42555fdef542b4399d2..a20da8c25b4f960224fb4d772aafea38c57e1656 100644 (file)
@@ -2770,9 +2770,9 @@ static int sd_revalidate_disk(struct gendisk *disk)
        max_xfer = sdkp->max_xfer_blocks;
        max_xfer <<= ilog2(sdp->sector_size) - 9;
 
-       max_xfer = min_not_zero(queue_max_hw_sectors(sdkp->disk->queue),
-                               max_xfer);
-       blk_queue_max_hw_sectors(sdkp->disk->queue, max_xfer);
+       sdkp->disk->queue->limits.max_sectors =
+               min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), max_xfer);
+
        set_capacity(disk, sdkp->capacity);
        sd_config_write_same(sdkp);
        kfree(buffer);
index 285f77544c36391a89b243001c3fc93d0703f46f..7dbbb29d24c6cf5290cd06a7a97df570a8860f18 100644 (file)
@@ -949,7 +949,7 @@ static int virtscsi_probe(struct virtio_device *vdev)
 {
        struct Scsi_Host *shost;
        struct virtio_scsi *vscsi;
-       int err, host_prot;
+       int err;
        u32 sg_elems, num_targets;
        u32 cmd_per_lun;
        u32 num_queues;
@@ -1009,6 +1009,8 @@ static int virtscsi_probe(struct virtio_device *vdev)
 
 #ifdef CONFIG_BLK_DEV_INTEGRITY
        if (virtio_has_feature(vdev, VIRTIO_SCSI_F_T10_PI)) {
+               int host_prot;
+
                host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION |
                            SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION |
                            SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION;
index 0cae1694014dfbbaba171187fdbd4fc835dc1546..b0f30fb68914220ea75b401dd52b7d537c00687e 100644 (file)
@@ -612,7 +612,7 @@ config SPI_XTENSA_XTFPGA
 
 config SPI_ZYNQMP_GQSPI
        tristate "Xilinx ZynqMP GQSPI controller"
-       depends on SPI_MASTER
+       depends on SPI_MASTER && HAS_DMA
        help
          Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
 
index 788e2b176a4f7707051bcc325538e7d2a6d599f4..acce90ac7371d58d94b47dc3cb1da029969fb95f 100644 (file)
@@ -40,6 +40,7 @@
 #define SPFI_CONTROL_SOFT_RESET                        BIT(11)
 #define SPFI_CONTROL_SEND_DMA                  BIT(10)
 #define SPFI_CONTROL_GET_DMA                   BIT(9)
+#define SPFI_CONTROL_SE                        BIT(8)
 #define SPFI_CONTROL_TMODE_SHIFT               5
 #define SPFI_CONTROL_TMODE_MASK                        0x7
 #define SPFI_CONTROL_TMODE_SINGLE              0
@@ -491,6 +492,7 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
        else if (xfer->tx_nbits == SPI_NBITS_QUAD &&
                 xfer->rx_nbits == SPI_NBITS_QUAD)
                val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT;
+       val |= SPFI_CONTROL_SE;
        spfi_writel(spfi, val, SPFI_CONTROL);
 }
 
index eb7d3a6fb14c0694b55e5286933256c5962043ce..f9deb84e4e551bdd9c42c8ac204c80c18f0f8579 100644 (file)
@@ -201,8 +201,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 {
        struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
 
-       if (spi_imx->dma_is_inited && (transfer->len > spi_imx->rx_wml)
-           && (transfer->len > spi_imx->tx_wml))
+       if (spi_imx->dma_is_inited
+           && transfer->len > spi_imx->rx_wml * sizeof(u32)
+           && transfer->len > spi_imx->tx_wml * sizeof(u32))
                return true;
        return false;
 }
index 87b20a511a6ba66cc4ba084df028a3c073691aa2..f23f36ebaf3dc700447da2e4da6e9b1b28e8ed82 100644 (file)
@@ -214,6 +214,7 @@ static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr,
        case GQSPI_SELECT_FLASH_CS_BOTH:
                instanceptr->genfifocs = GQSPI_GENFIFO_CS_LOWER |
                        GQSPI_GENFIFO_CS_UPPER;
+               break;
        case GQSPI_SELECT_FLASH_CS_UPPER:
                instanceptr->genfifocs = GQSPI_GENFIFO_CS_UPPER;
                break;
index dd616ff0ffc52542c3c8f8aaaf7c7d30bb9fd219..c7de64171c452325ab43884b501977a33f724b93 100644 (file)
@@ -693,6 +693,7 @@ static struct class *spidev_class;
 #ifdef CONFIG_OF
 static const struct of_device_id spidev_dt_ids[] = {
        { .compatible = "rohm,dh2228fv" },
+       { .compatible = "lineartechnology,ltc2488" },
        {},
 };
 MODULE_DEVICE_TABLE(of, spidev_dt_ids);
index bfa42620a3f607857978895a49451b9177964374..940781183fac4e450503c7b3cd5df6c30bde6d0c 100644 (file)
@@ -1266,6 +1266,7 @@ static const struct das1800_board *das1800_probe(struct comedi_device *dev)
                if (index == das1801hc || index == das1802hc)
                        return board;
                index = das1801hc;
+               break;
        default:
                dev_err(dev->class_dev,
                        "Board model: probe returned 0x%x (unknown, please report)\n",
index 9c934e6d2ea1114094921bd890eb0186a50f0e06..c61add46b4268b722eeaad74a0540a4a2c48f1e8 100644 (file)
@@ -40,7 +40,7 @@
 
 #define DEBUG_SUBSYSTEM D_OTHER
 
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 
 #include "../include/obd_support.h"
 #include "../include/lustre_debug.h"
index b0c8e235b982164bb170b53655ccfc8d01378d6b..69bdc8f29b59f4c1e1cbacabf7563a7ca1d66817 100644 (file)
@@ -1483,8 +1483,9 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
-       if (changed & BSS_CHANGED_ASSOC && priv->op_mode != NL80211_IFTYPE_AP) {
-               if (conf->assoc) {
+       if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) &&
+           priv->op_mode != NL80211_IFTYPE_AP) {
+               if (conf->assoc && conf->beacon_rate) {
                        CARDbUpdateTSF(priv, conf->beacon_rate->hw_value,
                                       conf->sync_tsf);
 
index 4e68b62193ed7781d3c32f4160878809acfc546d..cd77a064c772f1bbe897482d2372fe5bc6434328 100644 (file)
@@ -3998,7 +3998,13 @@ get_immediate:
        }
 
 transport_err:
-       iscsit_take_action_for_connection_exit(conn);
+       /*
+        * Avoid the normal connection failure code-path if this connection
+        * is still within LOGIN mode, and iscsi_np process context is
+        * responsible for cleaning up the early connection failure.
+        */
+       if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN)
+               iscsit_take_action_for_connection_exit(conn);
 out:
        return 0;
 }
@@ -4082,7 +4088,7 @@ reject:
 
 int iscsi_target_rx_thread(void *arg)
 {
-       int ret;
+       int ret, rc;
        u8 buffer[ISCSI_HDR_LEN], opcode;
        u32 checksum = 0, digest = 0;
        struct iscsi_conn *conn = arg;
@@ -4092,10 +4098,16 @@ int iscsi_target_rx_thread(void *arg)
         * connection recovery / failure event can be triggered externally.
         */
        allow_signal(SIGINT);
+       /*
+        * Wait for iscsi_post_login_handler() to complete before allowing
+        * incoming iscsi/tcp socket I/O, and/or failing the connection.
+        */
+       rc = wait_for_completion_interruptible(&conn->rx_login_comp);
+       if (rc < 0)
+               return 0;
 
        if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
                struct completion comp;
-               int rc;
 
                init_completion(&comp);
                rc = wait_for_completion_interruptible(&comp);
@@ -4532,7 +4544,18 @@ static void iscsit_logout_post_handler_closesession(
        struct iscsi_conn *conn)
 {
        struct iscsi_session *sess = conn->sess;
-       int sleep = cmpxchg(&conn->tx_thread_active, true, false);
+       int sleep = 1;
+       /*
+        * Traditional iscsi/tcp will invoke this logic from TX thread
+        * context during session logout, so clear tx_thread_active and
+        * sleep if iscsit_close_connection() has not already occured.
+        *
+        * Since iser-target invokes this logic from it's own workqueue,
+        * always sleep waiting for RX/TX thread shutdown to complete
+        * within iscsit_close_connection().
+        */
+       if (conn->conn_transport->transport_type == ISCSI_TCP)
+               sleep = cmpxchg(&conn->tx_thread_active, true, false);
 
        atomic_set(&conn->conn_logout_remove, 0);
        complete(&conn->conn_logout_comp);
@@ -4546,7 +4569,10 @@ static void iscsit_logout_post_handler_closesession(
 static void iscsit_logout_post_handler_samecid(
        struct iscsi_conn *conn)
 {
-       int sleep = cmpxchg(&conn->tx_thread_active, true, false);
+       int sleep = 1;
+
+       if (conn->conn_transport->transport_type == ISCSI_TCP)
+               sleep = cmpxchg(&conn->tx_thread_active, true, false);
 
        atomic_set(&conn->conn_logout_remove, 0);
        complete(&conn->conn_logout_comp);
@@ -4765,6 +4791,7 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
        struct iscsi_session *sess;
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
        struct se_session *se_sess, *se_sess_tmp;
+       LIST_HEAD(free_list);
        int session_count = 0;
 
        spin_lock_bh(&se_tpg->session_lock);
@@ -4786,14 +4813,17 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
                }
                atomic_set(&sess->session_reinstatement, 1);
                spin_unlock(&sess->conn_lock);
-               spin_unlock_bh(&se_tpg->session_lock);
 
-               iscsit_free_session(sess);
-               spin_lock_bh(&se_tpg->session_lock);
+               list_move_tail(&se_sess->sess_list, &free_list);
+       }
+       spin_unlock_bh(&se_tpg->session_lock);
+
+       list_for_each_entry_safe(se_sess, se_sess_tmp, &free_list, sess_list) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
 
+               iscsit_free_session(sess);
                session_count++;
        }
-       spin_unlock_bh(&se_tpg->session_lock);
 
        pr_debug("Released %d iSCSI Session(s) from Target Portal"
                        " Group: %hu\n", session_count, tpg->tpgt);
index 3d0fe4ff55904d00a702958a82413a33873de888..7e8f65e5448fdbda5645e3d5a836ad9f81408efa 100644 (file)
@@ -82,6 +82,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn)
        init_completion(&conn->conn_logout_comp);
        init_completion(&conn->rx_half_close_comp);
        init_completion(&conn->tx_half_close_comp);
+       init_completion(&conn->rx_login_comp);
        spin_lock_init(&conn->cmd_lock);
        spin_lock_init(&conn->conn_usage_lock);
        spin_lock_init(&conn->immed_queue_lock);
@@ -644,7 +645,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
                iscsit_start_nopin_timer(conn);
 }
 
-static int iscsit_start_kthreads(struct iscsi_conn *conn)
+int iscsit_start_kthreads(struct iscsi_conn *conn)
 {
        int ret = 0;
 
@@ -679,6 +680,7 @@ static int iscsit_start_kthreads(struct iscsi_conn *conn)
 
        return 0;
 out_tx:
+       send_sig(SIGINT, conn->tx_thread, 1);
        kthread_stop(conn->tx_thread);
        conn->tx_thread_active = false;
 out_bitmap:
@@ -689,7 +691,7 @@ out_bitmap:
        return ret;
 }
 
-int iscsi_post_login_handler(
+void iscsi_post_login_handler(
        struct iscsi_np *np,
        struct iscsi_conn *conn,
        u8 zero_tsih)
@@ -699,7 +701,6 @@ int iscsi_post_login_handler(
        struct se_session *se_sess = sess->se_sess;
        struct iscsi_portal_group *tpg = sess->tpg;
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
-       int rc;
 
        iscsit_inc_conn_usage_count(conn);
 
@@ -739,10 +740,6 @@ int iscsi_post_login_handler(
                        sess->sess_ops->InitiatorName);
                spin_unlock_bh(&sess->conn_lock);
 
-               rc = iscsit_start_kthreads(conn);
-               if (rc)
-                       return rc;
-
                iscsi_post_login_start_timers(conn);
                /*
                 * Determine CPU mask to ensure connection's RX and TX kthreads
@@ -751,15 +748,20 @@ int iscsi_post_login_handler(
                iscsit_thread_get_cpumask(conn);
                conn->conn_rx_reset_cpumask = 1;
                conn->conn_tx_reset_cpumask = 1;
-
+               /*
+                * Wakeup the sleeping iscsi_target_rx_thread() now that
+                * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state.
+                */
+               complete(&conn->rx_login_comp);
                iscsit_dec_conn_usage_count(conn);
+
                if (stop_timer) {
                        spin_lock_bh(&se_tpg->session_lock);
                        iscsit_stop_time2retain_timer(sess);
                        spin_unlock_bh(&se_tpg->session_lock);
                }
                iscsit_dec_session_usage_count(sess);
-               return 0;
+               return;
        }
 
        iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1);
@@ -800,10 +802,6 @@ int iscsi_post_login_handler(
                " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt);
        spin_unlock_bh(&se_tpg->session_lock);
 
-       rc = iscsit_start_kthreads(conn);
-       if (rc)
-               return rc;
-
        iscsi_post_login_start_timers(conn);
        /*
         * Determine CPU mask to ensure connection's RX and TX kthreads
@@ -812,10 +810,12 @@ int iscsi_post_login_handler(
        iscsit_thread_get_cpumask(conn);
        conn->conn_rx_reset_cpumask = 1;
        conn->conn_tx_reset_cpumask = 1;
-
+       /*
+        * Wakeup the sleeping iscsi_target_rx_thread() now that
+        * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state.
+        */
+       complete(&conn->rx_login_comp);
        iscsit_dec_conn_usage_count(conn);
-
-       return 0;
 }
 
 static void iscsi_handle_login_thread_timeout(unsigned long data)
@@ -1380,23 +1380,12 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        if (ret < 0)
                goto new_sess_out;
 
-       if (!conn->sess) {
-               pr_err("struct iscsi_conn session pointer is NULL!\n");
-               goto new_sess_out;
-       }
-
        iscsi_stop_login_thread_timer(np);
 
-       if (signal_pending(current))
-               goto new_sess_out;
-
        if (ret == 1) {
                tpg_np = conn->tpg_np;
 
-               ret = iscsi_post_login_handler(np, conn, zero_tsih);
-               if (ret < 0)
-                       goto new_sess_out;
-
+               iscsi_post_login_handler(np, conn, zero_tsih);
                iscsit_deaccess_np(np, tpg, tpg_np);
        }
 
index 1c7358081533ad1e3fb0533f424fa7749feda7d5..57aa0d0fd820f330c271836ecdc02c5a067179b2 100644 (file)
@@ -12,7 +12,8 @@ extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *);
 extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
 extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
 extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
-extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
+extern int iscsit_start_kthreads(struct iscsi_conn *);
+extern void iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
 extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *,
                                bool, bool);
 extern int iscsi_target_login_thread(void *);
index 8c02fa34716fae5a40dbf8cb09357bba5df2e7bd..f9cde91418367071d08c3a3ebe08dc44a1a1abe3 100644 (file)
@@ -17,6 +17,7 @@
  ******************************************************************************/
 
 #include <linux/ctype.h>
+#include <linux/kthread.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
@@ -361,10 +362,24 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
                ntohl(login_rsp->statsn), login->rsp_length);
 
        padding = ((-login->rsp_length) & 3);
+       /*
+        * Before sending the last login response containing the transition
+        * bit for full-feature-phase, go ahead and start up TX/RX threads
+        * now to avoid potential resource allocation failures after the
+        * final login response has been sent.
+        */
+       if (login->login_complete) {
+               int rc = iscsit_start_kthreads(conn);
+               if (rc) {
+                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                                           ISCSI_LOGIN_STATUS_NO_RESOURCES);
+                       return -1;
+               }
+       }
 
        if (conn->conn_transport->iscsit_put_login_tx(conn, login,
                                        login->rsp_length + padding) < 0)
-               return -1;
+               goto err;
 
        login->rsp_length               = 0;
        mutex_lock(&sess->cmdsn_mutex);
@@ -373,6 +388,23 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
        mutex_unlock(&sess->cmdsn_mutex);
 
        return 0;
+
+err:
+       if (login->login_complete) {
+               if (conn->rx_thread && conn->rx_thread_active) {
+                       send_sig(SIGINT, conn->rx_thread, 1);
+                       kthread_stop(conn->rx_thread);
+               }
+               if (conn->tx_thread && conn->tx_thread_active) {
+                       send_sig(SIGINT, conn->tx_thread, 1);
+                       kthread_stop(conn->tx_thread);
+               }
+               spin_lock(&iscsit_global->ts_bitmap_lock);
+               bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id,
+                                     get_order(1));
+               spin_unlock(&iscsit_global->ts_bitmap_lock);
+       }
+       return -1;
 }
 
 static void iscsi_target_sk_data_ready(struct sock *sk)
index 0b0de36474784987c781906243eabbed27ecab00..c2e9fea90b4a4bc16a0384d79fa9684c9f4176e0 100644 (file)
@@ -747,7 +747,7 @@ static ssize_t store_pi_prot_type(struct se_dev_attrib *da,
        if (!dev->transport->init_prot || !dev->transport->free_prot) {
                /* 0 is only allowed value for non-supporting backends */
                if (flag == 0)
-                       return 0;
+                       return count;
 
                pr_err("DIF protection not supported by backend: %s\n",
                       dev->transport->name);
@@ -1590,9 +1590,9 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
        u8 type = 0;
 
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
-               return 0;
+               return count;
        if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
-               return 0;
+               return count;
 
        if (dev->export_count) {
                pr_debug("Unable to process APTPL metadata while"
@@ -1658,22 +1658,32 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
                 * PR APTPL Metadata for Reservation
                 */
                case Opt_res_holder:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        res_holder = arg;
                        break;
                case Opt_res_type:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        type = (u8)arg;
                        break;
                case Opt_res_scope:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        break;
                case Opt_res_all_tg_pt:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        all_tg_pt = (int)arg;
                        break;
                case Opt_mapped_lun:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        mapped_lun = (u64)arg;
                        break;
                /*
@@ -1701,14 +1711,20 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
                        }
                        break;
                case Opt_tpgt:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        tpgt = (u16)arg;
                        break;
                case Opt_port_rtpi:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        break;
                case Opt_target_lun:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        target_lun = (u64)arg;
                        break;
                default:
@@ -1985,7 +2001,7 @@ static ssize_t target_core_store_alua_lu_gp(
 
        lu_gp_mem = dev->dev_alua_lu_gp_mem;
        if (!lu_gp_mem)
-               return 0;
+               return count;
 
        if (count > LU_GROUP_NAME_BUF) {
                pr_err("ALUA LU Group Alias too large!\n");
index 0fdbe43b7dad99479f7288584a0d95815c4dab72..5ab7100de17eb5694b162403ef43585c4bbceaf1 100644 (file)
@@ -1474,7 +1474,7 @@ core_scsi3_decode_spec_i_port(
        LIST_HEAD(tid_dest_list);
        struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp;
        unsigned char *buf, *ptr, proto_ident;
-       const unsigned char *i_str;
+       const unsigned char *i_str = NULL;
        char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN];
        sense_reason_t ret;
        u32 tpdl, tid_len = 0;
index 4703f403f31c0dd6cc9b4d31422bbc16387b20e7..384cf88944113892135b3ff253ed97bdc6b9c8b4 100644 (file)
@@ -333,6 +333,7 @@ static int rd_configure_device(struct se_device *dev)
        dev->dev_attrib.hw_block_size = RD_BLOCKSIZE;
        dev->dev_attrib.hw_max_sectors = UINT_MAX;
        dev->dev_attrib.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH;
+       dev->dev_attrib.is_nonrot = 1;
 
        rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++;
 
index b0744433315a80496a84d8d6f49e01300471f463..b5ba1ec3c35476361103d7dca47a1934cdd3289f 100644 (file)
@@ -454,10 +454,17 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
                    cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE1_PROT)
                        buf[4] = 0x5;
                else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT ||
-                       cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT)
+                        cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT)
                        buf[4] = 0x4;
        }
 
+       /* logical unit supports type 1 and type 3 protection */
+       if ((dev->transport->get_device_type(dev) == TYPE_DISK) &&
+           (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) &&
+           (dev->dev_attrib.pi_prot_type || cmd->se_sess->sess_prot_type)) {
+               buf[4] |= (0x3 << 3);
+       }
+
        /* Set HEADSUP, ORDSUP, SIMPSUP */
        buf[5] = 0x07;
 
index d5dd357ba57c4c6af785b4f915d9fccba6a4fa21..b49f97c734d00ddccb50379d3131c232651e96e5 100644 (file)
@@ -405,7 +405,6 @@ static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,
 static struct platform_driver hisi_thermal_driver = {
        .driver = {
                .name           = "hisi_thermal",
-               .owner          = THIS_MODULE,
                .pm             = &hisi_thermal_pm_ops,
                .of_match_table = of_hisi_thermal_match,
        },
index 4672250b329f4cec54ab243b55b41b127b1c48d0..63a448f9d93b66eedec7fde829983588fe6251f0 100644 (file)
@@ -229,7 +229,8 @@ static int allocate_power(struct thermal_zone_device *tz,
        struct thermal_instance *instance;
        struct power_allocator_params *params = tz->governor_data;
        u32 *req_power, *max_power, *granted_power, *extra_actor_power;
-       u32 total_req_power, max_allocatable_power;
+       u32 *weighted_req_power;
+       u32 total_req_power, max_allocatable_power, total_weighted_req_power;
        u32 total_granted_power, power_range;
        int i, num_actors, total_weight, ret = 0;
        int trip_max_desired_temperature = params->trip_max_desired_temperature;
@@ -247,16 +248,17 @@ static int allocate_power(struct thermal_zone_device *tz,
        }
 
        /*
-        * We need to allocate three arrays of the same size:
-        * req_power, max_power and granted_power.  They are going to
-        * be needed until this function returns.  Allocate them all
-        * in one go to simplify the allocation and deallocation
-        * logic.
+        * We need to allocate five arrays of the same size:
+        * req_power, max_power, granted_power, extra_actor_power and
+        * weighted_req_power.  They are going to be needed until this
+        * function returns.  Allocate them all in one go to simplify
+        * the allocation and deallocation logic.
         */
        BUILD_BUG_ON(sizeof(*req_power) != sizeof(*max_power));
        BUILD_BUG_ON(sizeof(*req_power) != sizeof(*granted_power));
        BUILD_BUG_ON(sizeof(*req_power) != sizeof(*extra_actor_power));
-       req_power = devm_kcalloc(&tz->device, num_actors * 4,
+       BUILD_BUG_ON(sizeof(*req_power) != sizeof(*weighted_req_power));
+       req_power = devm_kcalloc(&tz->device, num_actors * 5,
                                 sizeof(*req_power), GFP_KERNEL);
        if (!req_power) {
                ret = -ENOMEM;
@@ -266,8 +268,10 @@ static int allocate_power(struct thermal_zone_device *tz,
        max_power = &req_power[num_actors];
        granted_power = &req_power[2 * num_actors];
        extra_actor_power = &req_power[3 * num_actors];
+       weighted_req_power = &req_power[4 * num_actors];
 
        i = 0;
+       total_weighted_req_power = 0;
        total_req_power = 0;
        max_allocatable_power = 0;
 
@@ -289,13 +293,14 @@ static int allocate_power(struct thermal_zone_device *tz,
                else
                        weight = instance->weight;
 
-               req_power[i] = frac_to_int(weight * req_power[i]);
+               weighted_req_power[i] = frac_to_int(weight * req_power[i]);
 
                if (power_actor_get_max_power(cdev, tz, &max_power[i]))
                        continue;
 
                total_req_power += req_power[i];
                max_allocatable_power += max_power[i];
+               total_weighted_req_power += weighted_req_power[i];
 
                i++;
        }
@@ -303,8 +308,9 @@ static int allocate_power(struct thermal_zone_device *tz,
        power_range = pid_controller(tz, current_temp, control_temp,
                                     max_allocatable_power);
 
-       divvy_up_power(req_power, max_power, num_actors, total_req_power,
-                      power_range, granted_power, extra_actor_power);
+       divvy_up_power(weighted_req_power, max_power, num_actors,
+                      total_weighted_req_power, power_range, granted_power,
+                      extra_actor_power);
 
        total_granted_power = 0;
        i = 0;
index c8e35c1a43dcfd19145a6d1e24b132b25b5c6169..e0da3865e0600f8f23b6368be63fd662d5dda6d1 100644 (file)
@@ -1,6 +1,6 @@
 config EXYNOS_THERMAL
        tristate "Exynos thermal management unit driver"
-       depends on OF
+       depends on THERMAL_OF
        help
          If you say yes here you get support for the TMU (Thermal Management
          Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises
index 531f4b179871f63da7fea6f32af19b27af18e9a3..c96ff10b869efd941bfe8c32384d48b70b1c348d 100644 (file)
@@ -1296,7 +1296,6 @@ static struct thermal_zone_of_device_ops exynos_sensor_ops = {
 
 static int exynos_tmu_probe(struct platform_device *pdev)
 {
-       struct exynos_tmu_platform_data *pdata;
        struct exynos_tmu_data *data;
        int ret;
 
@@ -1318,8 +1317,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
        if (ret)
                goto err_sensor;
 
-       pdata = data->pdata;
-
        INIT_WORK(&data->irq_work, exynos_tmu_work);
 
        data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
@@ -1392,6 +1389,8 @@ err_clk_sec:
        if (!IS_ERR(data->clk_sec))
                clk_unprepare(data->clk_sec);
 err_sensor:
+       if (!IS_ERR_OR_NULL(data->regulator))
+               regulator_disable(data->regulator);
        thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
 
        return ret;
index 04659bfb888b73237257b75f944bf9130bc241b6..4ca211be4c0f197825be94f70be386af1c2cc33d 100644 (file)
@@ -1333,6 +1333,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
        return -ENODEV;
 
 unbind:
+       device_remove_file(&tz->device, &pos->weight_attr);
        device_remove_file(&tz->device, &pos->attr);
        sysfs_remove_link(&tz->device.kobj, pos->name);
        release_idr(&tz->idr, &tz->lock, pos->id);
index c9c27f69e101cfc9246a81ed1f187148b08193e6..ee8bfacf20716481a23a60325b5c99ba9da35508 100644 (file)
@@ -1108,19 +1108,29 @@ static void eraser(unsigned char c, struct tty_struct *tty)
  *     Locking: ctrl_lock
  */
 
-static void isig(int sig, struct tty_struct *tty)
+static void __isig(int sig, struct tty_struct *tty)
 {
-       struct n_tty_data *ldata = tty->disc_data;
        struct pid *tty_pgrp = tty_get_pgrp(tty);
        if (tty_pgrp) {
                kill_pgrp(tty_pgrp, sig, 1);
                put_pid(tty_pgrp);
        }
+}
 
-       if (!L_NOFLSH(tty)) {
+static void isig(int sig, struct tty_struct *tty)
+{
+       struct n_tty_data *ldata = tty->disc_data;
+
+       if (L_NOFLSH(tty)) {
+               /* signal only */
+               __isig(sig, tty);
+
+       } else { /* signal and flush */
                up_read(&tty->termios_rwsem);
                down_write(&tty->termios_rwsem);
 
+               __isig(sig, tty);
+
                /* clear echo buffer */
                mutex_lock(&ldata->output_lock);
                ldata->echo_head = ldata->echo_tail = 0;
index 76e65b714471d9eeb11ea12593adea987205daaa..15b4079a335e886ca62c422970c80ba8c93f9dfb 100644 (file)
@@ -1185,7 +1185,7 @@ config SERIAL_SC16IS7XX_CORE
 config SERIAL_SC16IS7XX
         tristate "SC16IS7xx serial support"
         select SERIAL_CORE
-        depends on I2C || SPI_MASTER
+        depends on (SPI_MASTER && !I2C) || I2C
         help
           This selects support for SC16IS7xx serial ports.
           Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
index 50cf5b10ceed98022cbc44609acd280ef2beba81..fd27e986b1dd3437dfd2560ec11efd8def7bf254 100644 (file)
@@ -2310,8 +2310,8 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
        void __iomem *base;
 
        base = devm_ioremap_resource(dev, mmiobase);
-       if (!base)
-               return -ENOMEM;
+       if (IS_ERR(base))
+               return PTR_ERR(base);
 
        index = pl011_probe_dt_alias(index, dev);
 
index a57301a6fe427027788aa2153547928597c71ed1..679709f51fd4cfe4739fc2edb433cc4badaf0227 100644 (file)
@@ -950,7 +950,7 @@ static int etraxfs_uart_remove(struct platform_device *pdev)
 
        port = platform_get_drvdata(pdev);
        uart_remove_one_port(&etraxfs_uart_driver, port);
-       etraxfs_uart_ports[pdev->id] = NULL;
+       etraxfs_uart_ports[port->line] = NULL;
 
        return 0;
 }
index 2c90dc31bfaabc0242e168dd688faadadd9f164a..54fdc7866ea17423836827ee374c1ecfd0b5257d 100644 (file)
@@ -1121,11 +1121,6 @@ static int imx_startup(struct uart_port *port)
 
        writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
 
-       /* Can we enable the DMA support? */
-       if (is_imx6q_uart(sport) && !uart_console(port) &&
-           !sport->dma_is_inited)
-               imx_uart_dma_init(sport);
-
        spin_lock_irqsave(&sport->port.lock, flags);
        /* Reset fifo's and state machines */
        i = 100;
@@ -1143,9 +1138,6 @@ static int imx_startup(struct uart_port *port)
        writel(USR1_RTSD, sport->port.membase + USR1);
        writel(USR2_ORE, sport->port.membase + USR2);
 
-       if (sport->dma_is_inited && !sport->dma_is_enabled)
-               imx_enable_dma(sport);
-
        temp = readl(sport->port.membase + UCR1);
        temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
 
@@ -1316,6 +1308,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                        } else {
                                ucr2 |= UCR2_CTSC;
                        }
+
+                       /* Can we enable the DMA support? */
+                       if (is_imx6q_uart(sport) && !uart_console(port)
+                               && !sport->dma_is_inited)
+                               imx_uart_dma_init(sport);
                } else {
                        termios->c_cflag &= ~CRTSCTS;
                }
@@ -1432,6 +1429,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
                imx_enable_ms(&sport->port);
 
+       if (sport->dma_is_inited && !sport->dma_is_enabled)
+               imx_enable_dma(sport);
        spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
index 9e6576004a427e51cac6f1b59237248a706332f8..5ccc698cbbfa1ad9bde91200ea5907753fbb4b78 100644 (file)
@@ -354,6 +354,26 @@ static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val)
                     (reg << SC16IS7XX_REG_SHIFT) | port->line, val);
 }
 
+static void sc16is7xx_fifo_read(struct uart_port *port, unsigned int rxlen)
+{
+       struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+       u8 addr = (SC16IS7XX_RHR_REG << SC16IS7XX_REG_SHIFT) | port->line;
+
+       regcache_cache_bypass(s->regmap, true);
+       regmap_raw_read(s->regmap, addr, s->buf, rxlen);
+       regcache_cache_bypass(s->regmap, false);
+}
+
+static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send)
+{
+       struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+       u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | port->line;
+
+       regcache_cache_bypass(s->regmap, true);
+       regmap_raw_write(s->regmap, addr, s->buf, to_send);
+       regcache_cache_bypass(s->regmap, false);
+}
+
 static void sc16is7xx_port_update(struct uart_port *port, u8 reg,
                                  u8 mask, u8 val)
 {
@@ -508,10 +528,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
                        s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
                        bytes_read = 1;
                } else {
-                       regcache_cache_bypass(s->regmap, true);
-                       regmap_raw_read(s->regmap, SC16IS7XX_RHR_REG,
-                                       s->buf, rxlen);
-                       regcache_cache_bypass(s->regmap, false);
+                       sc16is7xx_fifo_read(port, rxlen);
                        bytes_read = rxlen;
                }
 
@@ -591,9 +608,8 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
                        s->buf[i] = xmit->buf[xmit->tail];
                        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                }
-               regcache_cache_bypass(s->regmap, true);
-               regmap_raw_write(s->regmap, SC16IS7XX_THR_REG, s->buf, to_send);
-               regcache_cache_bypass(s->regmap, false);
+
+               sc16is7xx_fifo_write(port, to_send);
        }
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
index 7ae1592f7ec9731c4dab1d3a12b980420aade634..f36852067f20e61ebaf67269ec08c37ea342c06a 100644 (file)
@@ -1418,7 +1418,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        mutex_lock(&port->mutex);
        uart_shutdown(tty, state);
        tty_port_tty_set(port, NULL);
-       tty->closing = 0;
+
        spin_lock_irqsave(&port->lock, flags);
 
        if (port->blocked_open) {
@@ -1444,6 +1444,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        mutex_unlock(&port->mutex);
 
        tty_ldisc_flush(tty);
+       tty->closing = 0;
 }
 
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
index ea27804d87af9ec2485b1043f8ad97b30c05713f..381a2b13682c1a587a81e9bab781bcccdc669332 100644 (file)
@@ -356,6 +356,7 @@ int paste_selection(struct tty_struct *tty)
                        schedule();
                        continue;
                }
+               __set_current_state(TASK_RUNNING);
                count = sel_buffer_lth - pasted;
                count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL,
                                              count);
index 8fe52989b380155926c6865721e9ba16e2a60685..4462d167900c515abbf205b2b6134016c0933390 100644 (file)
@@ -742,6 +742,8 @@ static void visual_init(struct vc_data *vc, int num, int init)
        __module_get(vc->vc_sw->owner);
        vc->vc_num = num;
        vc->vc_display_fg = &master_display_fg;
+       if (vc->vc_uni_pagedir_loc)
+               con_free_unimap(vc);
        vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
        vc->vc_uni_pagedir = NULL;
        vc->vc_hi_font_mask = 0;
index 74fea4fa41b156248ce6d7116db02b54990066a9..3ad48e1c0c57e1722311c8393ad3bd21712fa1e7 100644 (file)
@@ -1024,7 +1024,18 @@ static struct platform_driver ci_hdrc_driver = {
        },
 };
 
-module_platform_driver(ci_hdrc_driver);
+static int __init ci_hdrc_platform_register(void)
+{
+       ci_hdrc_host_driver_init();
+       return platform_driver_register(&ci_hdrc_driver);
+}
+module_init(ci_hdrc_platform_register);
+
+static void __exit ci_hdrc_platform_unregister(void)
+{
+       platform_driver_unregister(&ci_hdrc_driver);
+}
+module_exit(ci_hdrc_platform_unregister);
 
 MODULE_ALIAS("platform:ci_hdrc");
 MODULE_LICENSE("GPL v2");
index 6cf87b8b13a8a606b5ccf680e4635fcbc44874a1..7161439def19aa265c9f36530d3d97d63ecc51a7 100644 (file)
@@ -249,9 +249,12 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
        rdrv->name      = "host";
        ci->roles[CI_ROLE_HOST] = rdrv;
 
+       return 0;
+}
+
+void ci_hdrc_host_driver_init(void)
+{
        ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides);
        orig_bus_suspend = ci_ehci_hc_driver.bus_suspend;
        ci_ehci_hc_driver.bus_suspend = ci_ehci_bus_suspend;
-
-       return 0;
 }
index 5707bf379bfb4b7ce98ff4a79d585619d1c64b48..0f12f131bdd3f22671eaf170476e2511950fa1be 100644 (file)
@@ -5,6 +5,7 @@
 
 int ci_hdrc_host_init(struct ci_hdrc *ci);
 void ci_hdrc_host_destroy(struct ci_hdrc *ci);
+void ci_hdrc_host_driver_init(void);
 
 #else
 
@@ -18,6 +19,11 @@ static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci)
 
 }
 
+static void ci_hdrc_host_driver_init(void)
+{
+
+}
+
 #endif
 
 #endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
index 519a77ba214cce4c4580b54856c74ba9e3af5342..b30e7423549b04b0e7d442a128048b4221c68062 100644 (file)
@@ -1944,6 +1944,7 @@ static void __exit acm_exit(void)
        usb_deregister(&acm_driver);
        tty_unregister_driver(acm_tty_driver);
        put_tty_driver(acm_tty_driver);
+       idr_destroy(&acm_minors);
 }
 
 module_init(acm_init);
index 0e6f968e93fe8a9f31f7de7199fa778b60b2f900..01c0c0477a9e93d1c8e1150b80763f5ee6c90a02 100644 (file)
@@ -242,7 +242,7 @@ static int __init ulpi_init(void)
 {
        return bus_register(&ulpi_bus);
 }
-module_init(ulpi_init);
+subsys_initcall(ulpi_init);
 
 static void __exit ulpi_exit(void)
 {
index be5b2074f9066a8c9ca3e79289117f67d52b1063..cbcd0920fb5121ba44bd7c87de9a3b3fdd9f51d6 100644 (file)
@@ -1022,9 +1022,12 @@ static int register_root_hub(struct usb_hcd *hcd)
                                dev_name(&usb_dev->dev), retval);
                return (retval < 0) ? retval : -EMSGSIZE;
        }
-       if (usb_dev->speed == USB_SPEED_SUPER) {
+
+       if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) {
                retval = usb_get_bos_descriptor(usb_dev);
-               if (retval < 0) {
+               if (!retval) {
+                       usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
+               } else if (usb_dev->speed == USB_SPEED_SUPER) {
                        mutex_unlock(&usb_bus_list_lock);
                        dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
                                        dev_name(&usb_dev->dev), retval);
index 43cb2f2e3b4375aee6c362e8b08d5f2b71865d8f..73dfa194160b78fba6bec233b667b00bceac6cb1 100644 (file)
@@ -122,7 +122,7 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
        return usb_get_intfdata(hdev->actconfig->interface[0]);
 }
 
-static int usb_device_supports_lpm(struct usb_device *udev)
+int usb_device_supports_lpm(struct usb_device *udev)
 {
        /* USB 2.1 (and greater) devices indicate LPM support through
         * their USB 2.0 Extended Capabilities BOS descriptor.
index 7eb1e26798e5f293a3f2bc508dd268bbecdb63f1..457255a3306a3c2837674d22aa9560bf30842220 100644 (file)
@@ -65,6 +65,7 @@ extern int  usb_hub_init(void);
 extern void usb_hub_cleanup(void);
 extern int usb_major_init(void);
 extern void usb_major_cleanup(void);
+extern int usb_device_supports_lpm(struct usb_device *udev);
 
 #ifdef CONFIG_PM
 
index 2ef3c8d6a9dbd3b5b8270cb5af230d793e0d7230..69e769c35cf5dc798fb34a6924c19726690592a2 100644 (file)
@@ -727,6 +727,10 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY");
                ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
                break;
+       case USB_REQ_SET_INTERFACE:
+               dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE");
+               dwc->start_config_issued = false;
+               /* Fall through */
        default:
                dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver");
                ret = dwc3_ep0_delegate_req(dwc, ctrl);
index f7f35a36c09a06eab17ef2e5af013ee3de2b5b8e..6df9715a4bcd31179cb190100df45b2dd975a0d2 100644 (file)
@@ -699,6 +699,10 @@ static inline int hidg_get_minor(void)
        int ret;
 
        ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL);
+       if (ret >= HIDG_MINORS) {
+               ida_simple_remove(&hidg_ida, ret);
+               ret = -ENODEV;
+       }
 
        return ret;
 }
index 44173df272739543a6b3168323073dba45239760..357f63f47b42aba69d92e24346963645227d39e2 100644 (file)
@@ -1248,7 +1248,15 @@ static struct config_item_type printer_func_type = {
 
 static inline int gprinter_get_minor(void)
 {
-       return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
+       int ret;
+
+       ret = ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
+       if (ret >= PRINTER_MINORS) {
+               ida_simple_remove(&printer_ida, ret);
+               ret = -ENODEV;
+       }
+
+       return ret;
 }
 
 static inline void gprinter_put_minor(int minor)
index 6d3eb8b00a488446db954334e80ac12eccf0d5cf..53186154725330d4c1f710e4829d4a8b25b614cd 100644 (file)
@@ -1162,14 +1162,14 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
                        factor = 1000;
                } else {
                        ep_desc = &hs_epin_desc;
-                       factor = 125;
+                       factor = 8000;
                }
 
                /* pre-compute some values for iso_complete() */
                uac2->p_framesize = opts->p_ssize *
                                    num_channels(opts->p_chmask);
                rate = opts->p_srate * uac2->p_framesize;
-               uac2->p_interval = (1 << (ep_desc->bInterval - 1)) * factor;
+               uac2->p_interval = factor / (1 << (ep_desc->bInterval - 1));
                uac2->p_pktsize = min_t(unsigned int, rate / uac2->p_interval,
                                        prm->max_psize);
 
index b04980cf6dc42108f4861e4dfa7285dd4fe56af9..1efa61265d8d49c5116027c8e3555ae70b9cc12c 100644 (file)
@@ -779,7 +779,7 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req)
        /* The current hw dequeue pointer */
        tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0));
        deq_ptr_64 = tmp_32;
-       tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(1));
+       tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1(0));
        deq_ptr_64 |= ((u64)tmp_32 << 32);
 
        /* we have the dma addr of next bd that will be fetched by hardware */
index d32160d6463f5fd3ca16442cdb37f0f0289fb5dc..5da37c957b53ce34bd9820ebfd57b9f20a5815c4 100644 (file)
@@ -2167,7 +2167,7 @@ static int mv_udc_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       udc->phy_regs = ioremap(r->start, resource_size(r));
+       udc->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
        if (udc->phy_regs == NULL) {
                dev_err(&pdev->dev, "failed to map phy I/O memory\n");
                return -EBUSY;
index d69c35558f6852beecd1bfc85acee35c26781ec8..89ed5e71a1991e0cd249c48b18bd04dd67bacf91 100644 (file)
@@ -60,13 +60,15 @@ static DEFINE_MUTEX(udc_lock);
 int usb_gadget_map_request(struct usb_gadget *gadget,
                struct usb_request *req, int is_in)
 {
+       struct device *dev = gadget->dev.parent;
+
        if (req->length == 0)
                return 0;
 
        if (req->num_sgs) {
                int     mapped;
 
-               mapped = dma_map_sg(&gadget->dev, req->sg, req->num_sgs,
+               mapped = dma_map_sg(dev, req->sg, req->num_sgs,
                                is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
                if (mapped == 0) {
                        dev_err(&gadget->dev, "failed to map SGs\n");
@@ -75,11 +77,11 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
 
                req->num_mapped_sgs = mapped;
        } else {
-               req->dma = dma_map_single(&gadget->dev, req->buf, req->length,
+               req->dma = dma_map_single(dev, req->buf, req->length,
                                is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 
-               if (dma_mapping_error(&gadget->dev, req->dma)) {
-                       dev_err(&gadget->dev, "failed to map buffer\n");
+               if (dma_mapping_error(dev, req->dma)) {
+                       dev_err(dev, "failed to map buffer\n");
                        return -EFAULT;
                }
        }
@@ -95,12 +97,12 @@ void usb_gadget_unmap_request(struct usb_gadget *gadget,
                return;
 
        if (req->num_mapped_sgs) {
-               dma_unmap_sg(&gadget->dev, req->sg, req->num_mapped_sgs,
+               dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs,
                                is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 
                req->num_mapped_sgs = 0;
        } else {
-               dma_unmap_single(&gadget->dev, req->dma, req->length,
+               dma_unmap_single(gadget->dev.parent, req->dma, req->length,
                                is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
        }
 }
@@ -321,6 +323,7 @@ err4:
 
 err3:
        put_device(&udc->dev);
+       device_del(&gadget->dev);
 
 err2:
        put_device(&gadget->dev);
index f7d561ed3c236290aa90334b90bd52cbfa9f7632..d029bbe9eb36a884fed45fd6f648bfca51199d65 100644 (file)
@@ -981,10 +981,6 @@ rescan_all:
                int                     completed, modified;
                __hc32                  *prev;
 
-               /* Is this ED already invisible to the hardware? */
-               if (ed->state == ED_IDLE)
-                       goto ed_idle;
-
                /* only take off EDs that the HC isn't using, accounting for
                 * frame counter wraps and EDs with partially retired TDs
                 */
@@ -1012,12 +1008,10 @@ skip_ed:
                }
 
                /* ED's now officially unlinked, hc doesn't see */
-               ed->state = ED_IDLE;
                ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
                ed->hwNextED = 0;
                wmb();
                ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE);
-ed_idle:
 
                /* reentrancy:  if we drop the schedule lock, someone might
                 * have modified this list.  normally it's just prepending
@@ -1088,6 +1082,7 @@ rescan_this:
                if (list_empty(&ed->td_list)) {
                        *last = ed->ed_next;
                        ed->ed_next = NULL;
+                       ed->state = ED_IDLE;
                        list_del(&ed->in_use_list);
                } else if (ohci->rh_state == OHCI_RH_RUNNING) {
                        *last = ed->ed_next;
index e9a6eec39142584032f777aa6101c00604b5ccf5..cfcfadfc94fc25b8e10d788e59514c146d32ccc1 100644 (file)
@@ -58,7 +58,7 @@
 #define CCR_PM_CKRNEN    0x0002
 #define CCR_PM_USBPW1    0x0004
 #define CCR_PM_USBPW2    0x0008
-#define CCR_PM_USBPW3    0x0008
+#define CCR_PM_USBPW3    0x0010
 #define CCR_PM_PMEE      0x0100
 #define CCR_PM_PMES      0x8000
 
index e75c565feb53ef3022312c047268367de71ae059..78241b5550df877fb09189936867f7821e09d11a 100644 (file)
@@ -484,10 +484,13 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
        u32 pls = status_reg & PORT_PLS_MASK;
 
        /* resume state is a xHCI internal state.
-        * Do not report it to usb core.
+        * Do not report it to usb core, instead, pretend to be U3,
+        * thus usb core knows it's not ready for transfer
         */
-       if (pls == XDEV_RESUME)
+       if (pls == XDEV_RESUME) {
+               *status |= USB_SS_PORT_LS_U3;
                return;
+       }
 
        /* When the CAS bit is set then warm reset
         * should be performed on port
@@ -588,7 +591,14 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                status |= USB_PORT_STAT_C_RESET << 16;
        /* USB3.0 only */
        if (hcd->speed == HCD_USB3) {
-               if ((raw_port_status & PORT_PLC))
+               /* Port link change with port in resume state should not be
+                * reported to usbcore, as this is an internal state to be
+                * handled by xhci driver. Reporting PLC to usbcore may
+                * cause usbcore clearing PLC first and port change event
+                * irq won't be generated.
+                */
+               if ((raw_port_status & PORT_PLC) &&
+                       (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME)
                        status |= USB_PORT_STAT_C_LINK_STATE << 16;
                if ((raw_port_status & PORT_WRC))
                        status |= USB_PORT_STAT_C_BH_RESET << 16;
@@ -1120,10 +1130,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
        spin_lock_irqsave(&xhci->lock, flags);
 
        if (hcd->self.root_hub->do_remote_wakeup) {
-               if (bus_state->resuming_ports) {
+               if (bus_state->resuming_ports ||        /* USB2 */
+                   bus_state->port_remote_wakeup) {    /* USB3 */
                        spin_unlock_irqrestore(&xhci->lock, flags);
-                       xhci_dbg(xhci, "suspend failed because "
-                                               "a port is resuming\n");
+                       xhci_dbg(xhci, "suspend failed because a port is resuming\n");
                        return -EBUSY;
                }
        }
index f8336408ef07c4354ad54c43e988b6b43272eea0..9a8c936cd42c18ef72a695d45c7e4ce2e893f8b0 100644 (file)
@@ -1427,10 +1427,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
                /* Attempt to use the ring cache */
                if (virt_dev->num_rings_cached == 0)
                        return -ENOMEM;
+               virt_dev->num_rings_cached--;
                virt_dev->eps[ep_index].new_ring =
                        virt_dev->ring_cache[virt_dev->num_rings_cached];
                virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
-               virt_dev->num_rings_cached--;
                xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
                                        1, type);
        }
@@ -1792,7 +1792,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
        int size;
        int i, j, num_ports;
 
-       del_timer_sync(&xhci->cmd_timer);
+       if (timer_pending(&xhci->cmd_timer))
+               del_timer_sync(&xhci->cmd_timer);
 
        /* Free the Event Ring Segment Table and the actual Event Ring */
        size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
index 4a4cb1d91ac8465d5ff274f5ded1a62e299cf92f..5590eac2b22df26ea4150d7bb8a8e1eeb2406ae3 100644 (file)
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/acpi.h>
 
 #include "xhci.h"
 #include "xhci-trace.h"
 
+#define PORT2_SSIC_CONFIG_REG2 0x883c
+#define PROG_DONE              (1 << 30)
+#define SSIC_PORT_UNUSED       (1 << 31)
+
 /* Device for a quirk */
 #define PCI_VENDOR_ID_FRESCO_LOGIC     0x1b73
 #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
@@ -176,20 +181,63 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 }
 
 /*
+ * In some Intel xHCI controllers, in order to get D3 working,
+ * through a vendor specific SSIC CONFIG register at offset 0x883c,
+ * SSIC PORT need to be marked as "unused" before putting xHCI
+ * into D3. After D3 exit, the SSIC port need to be marked as "used".
+ * Without this change, xHCI might not enter D3 state.
  * Make sure PME works on some Intel xHCI controllers by writing 1 to clear
  * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
  */
-static void xhci_pme_quirk(struct xhci_hcd *xhci)
+static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)
 {
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
        u32 val;
        void __iomem *reg;
 
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+                pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
+
+               reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;
+
+               /* Notify SSIC that SSIC profile programming is not done */
+               val = readl(reg) & ~PROG_DONE;
+               writel(val, reg);
+
+               /* Mark SSIC port as unused(suspend) or used(resume) */
+               val = readl(reg);
+               if (suspend)
+                       val |= SSIC_PORT_UNUSED;
+               else
+                       val &= ~SSIC_PORT_UNUSED;
+               writel(val, reg);
+
+               /* Notify SSIC that SSIC profile programming is done */
+               val = readl(reg) | PROG_DONE;
+               writel(val, reg);
+               readl(reg);
+       }
+
        reg = (void __iomem *) xhci->cap_regs + 0x80a4;
        val = readl(reg);
        writel(val | BIT(28), reg);
        readl(reg);
 }
 
+#ifdef CONFIG_ACPI
+static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
+{
+       static const u8 intel_dsm_uuid[] = {
+               0xb7, 0x0c, 0x34, 0xac, 0x01, 0xe9, 0xbf, 0x45,
+               0xb7, 0xe6, 0x2b, 0x34, 0xec, 0x93, 0x1e, 0x23,
+       };
+       acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1, NULL);
+}
+#else
+       static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
+#endif /* CONFIG_ACPI */
+
 /* called during probe() after chip reset completes */
 static int xhci_pci_setup(struct usb_hcd *hcd)
 {
@@ -263,6 +311,9 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                        HCC_MAX_PSA(xhci->hcc_params) >= 4)
                xhci->shared_hcd->can_do_streams = 1;
 
+       if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
+               xhci_pme_acpi_rtd3_enable(dev);
+
        /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
        pm_runtime_put_noidle(&dev->dev);
 
@@ -307,7 +358,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
                pdev->no_d3cold = true;
 
        if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
-               xhci_pme_quirk(xhci);
+               xhci_pme_quirk(hcd, true);
 
        return xhci_suspend(xhci, do_wakeup);
 }
@@ -340,7 +391,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
                usb_enable_intel_xhci_ports(pdev);
 
        if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
-               xhci_pme_quirk(xhci);
+               xhci_pme_quirk(hcd, false);
 
        retval = xhci_resume(xhci, hibernated);
        return retval;
index 94416ff7081071e3f32a682493e6a34bb8d359a8..32f4d564494a9f48cfebd328e61d3c281387d252 100644 (file)
@@ -82,7 +82,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
                return 0;
        /* offset in TRBs */
        segment_offset = trb - seg->trbs;
-       if (segment_offset > TRBS_PER_SEGMENT)
+       if (segment_offset >= TRBS_PER_SEGMENT)
                return 0;
        return seg->dma + (segment_offset * sizeof(*trb));
 }
@@ -1546,6 +1546,9 @@ static void handle_port_status(struct xhci_hcd *xhci,
                usb_hcd_resume_root_hub(hcd);
        }
 
+       if (hcd->speed == HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
+               bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
+
        if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
                xhci_dbg(xhci, "port resume event for port %d\n", port_id);
 
index 7da0d6043d33e13afa3ce4db45d5dfa54b4d3d22..526ebc0c7e720b9d766bcf6abf1bc65672e584bb 100644 (file)
@@ -3453,6 +3453,9 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
                        return -EINVAL;
        }
 
+       if (virt_dev->tt_info)
+               old_active_eps = virt_dev->tt_info->active_eps;
+
        if (virt_dev->udev != udev) {
                /* If the virt_dev and the udev does not match, this virt_dev
                 * may belong to another udev.
index 31e46cc55807a83a69f9e6e8ce9e89f176786215..ed2ebf647c380ebbdfe647544fb137283219cf87 100644 (file)
@@ -285,6 +285,7 @@ struct xhci_op_regs {
 #define XDEV_U0                (0x0 << 5)
 #define XDEV_U2                (0x2 << 5)
 #define XDEV_U3                (0x3 << 5)
+#define XDEV_INACTIVE  (0x6 << 5)
 #define XDEV_RESUME    (0xf << 5)
 /* true: port has power (see HCC_PPC) */
 #define PORT_POWER     (1 << 9)
index 19b85ee98a7247c46089e023676633e70eb498df..876423b8892c96f80930fa7a103f36370e519dfe 100644 (file)
@@ -1099,6 +1099,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
        { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x68c0, 0xff),
          .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC73xx */
+       { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x9041, 0xff),
+         .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC7305/MC7355 */
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
index 9c63897b3a564012ea63f99b9e5e73bc48b93d36..d156545728c2ab5b8bb81cf7537aa8a60805c08a 100644 (file)
@@ -145,7 +145,6 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_SWI(0x1199, 0x901c)},   /* Sierra Wireless EM7700 */
        {DEVICE_SWI(0x1199, 0x901f)},   /* Sierra Wireless EM7355 */
        {DEVICE_SWI(0x1199, 0x9040)},   /* Sierra Wireless Modem */
-       {DEVICE_SWI(0x1199, 0x9041)},   /* Sierra Wireless MC7305/MC7355 */
        {DEVICE_SWI(0x1199, 0x9051)},   /* Netgear AirCard 340U */
        {DEVICE_SWI(0x1199, 0x9053)},   /* Sierra Wireless Modem */
        {DEVICE_SWI(0x1199, 0x9054)},   /* Sierra Wireless Modem */
@@ -158,6 +157,7 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_SWI(0x413c, 0x81a4)},   /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81a8)},   /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81a9)},   /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
+       {DEVICE_SWI(0x413c, 0x81b1)},   /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
 
        /* Huawei devices */
        {DEVICE_HWI(0x03f0, 0x581d)},   /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
index 46179a0828ebcbad9a78c11dad8044edff27664a..07d1ecd564f79d9c51798f6941b1295d794d468c 100644 (file)
@@ -289,6 +289,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68AA, 0xFF, 0xFF, 0xFF),
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
        },
+       { USB_DEVICE(0x1199, 0x68AB) }, /* Sierra Wireless AR8550 */
        /* AT&T Direct IP LTE modems */
        { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF),
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
index caf188800c679e7f24fc329903848a8c1f64d41a..6b2479123de7762f7145c93fdcd58efb11f51093 100644 (file)
@@ -2065,6 +2065,18 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_READ_DISC_INFO ),
 
+/* Reported by Oliver Neukum <oneukum@suse.com>
+ * This device morphes spontaneously into another device if the access
+ * pattern of Windows isn't followed. Thus writable media would be dirty
+ * if the initial instance is used. So the device is limited to its
+ * virtual CD.
+ * And yes, the concept that BCD goes up to 9 is not heeded */
+UNUSUAL_DEV( 0x19d2, 0x1225, 0x0000, 0xffff,
+               "ZTE,Incorporated",
+               "ZTE WCDMA Technologies MSM",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_SINGLE_LUN ),
+
 /* Reported by Sven Geggus <sven-usbst@geggus.net>
  * This encrypted pen drive returns bogus data for the initial READ(10).
  */
@@ -2074,6 +2086,17 @@ UNUSUAL_DEV(  0x1b1c, 0x1ab5, 0x0200, 0x0200,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_INITIAL_READ10 ),
 
+/* Reported by Hans de Goede <hdegoede@redhat.com>
+ * These are mini projectors using USB for both power and video data transport
+ * The usb-storage interface is a virtual windows driver CD, which the gm12u320
+ * driver automatically converts into framebuffer & kms dri device nodes.
+ */
+UNUSUAL_DEV( 0x1de1, 0xc102, 0x0000, 0xffff,
+               "Grain-media Technology Corp.",
+               "USB3.0 Device GM12U320",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_DEVICE ),
+
 /* Patch by Richard Schütz <r.schtz@t-online.de>
  * This external hard drive enclosure uses a JMicron chip which
  * needs the US_FL_IGNORE_RESIDUE flag to work properly. */
index 2fb29dfeffbd7fa70a8a881f025d73ffd50b0b25..563c510f285c47d2a7362a4da8729fdc38e1dee0 100644 (file)
@@ -689,6 +689,23 @@ struct vfio_device *vfio_device_get_from_dev(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(vfio_device_get_from_dev);
 
+static struct vfio_device *vfio_device_get_from_name(struct vfio_group *group,
+                                                    char *buf)
+{
+       struct vfio_device *device;
+
+       mutex_lock(&group->device_lock);
+       list_for_each_entry(device, &group->device_list, group_next) {
+               if (!strcmp(dev_name(device->dev), buf)) {
+                       vfio_device_get(device);
+                       break;
+               }
+       }
+       mutex_unlock(&group->device_lock);
+
+       return device;
+}
+
 /*
  * Caller must hold a reference to the vfio_device
  */
@@ -1198,53 +1215,53 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
 {
        struct vfio_device *device;
        struct file *filep;
-       int ret = -ENODEV;
+       int ret;
 
        if (0 == atomic_read(&group->container_users) ||
            !group->container->iommu_driver || !vfio_group_viable(group))
                return -EINVAL;
 
-       mutex_lock(&group->device_lock);
-       list_for_each_entry(device, &group->device_list, group_next) {
-               if (strcmp(dev_name(device->dev), buf))
-                       continue;
+       device = vfio_device_get_from_name(group, buf);
+       if (!device)
+               return -ENODEV;
 
-               ret = device->ops->open(device->device_data);
-               if (ret)
-                       break;
-               /*
-                * We can't use anon_inode_getfd() because we need to modify
-                * the f_mode flags directly to allow more than just ioctls
-                */
-               ret = get_unused_fd_flags(O_CLOEXEC);
-               if (ret < 0) {
-                       device->ops->release(device->device_data);
-                       break;
-               }
+       ret = device->ops->open(device->device_data);
+       if (ret) {
+               vfio_device_put(device);
+               return ret;
+       }
 
-               filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops,
-                                          device, O_RDWR);
-               if (IS_ERR(filep)) {
-                       put_unused_fd(ret);
-                       ret = PTR_ERR(filep);
-                       device->ops->release(device->device_data);
-                       break;
-               }
+       /*
+        * We can't use anon_inode_getfd() because we need to modify
+        * the f_mode flags directly to allow more than just ioctls
+        */
+       ret = get_unused_fd_flags(O_CLOEXEC);
+       if (ret < 0) {
+               device->ops->release(device->device_data);
+               vfio_device_put(device);
+               return ret;
+       }
 
-               /*
-                * TODO: add an anon_inode interface to do this.
-                * Appears to be missing by lack of need rather than
-                * explicitly prevented.  Now there's need.
-                */
-               filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+       filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops,
+                                  device, O_RDWR);
+       if (IS_ERR(filep)) {
+               put_unused_fd(ret);
+               ret = PTR_ERR(filep);
+               device->ops->release(device->device_data);
+               vfio_device_put(device);
+               return ret;
+       }
+
+       /*
+        * TODO: add an anon_inode interface to do this.
+        * Appears to be missing by lack of need rather than
+        * explicitly prevented.  Now there's need.
+        */
+       filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
 
-               vfio_device_get(device);
-               atomic_inc(&group->container_users);
+       atomic_inc(&group->container_users);
 
-               fd_install(ret, filep);
-               break;
-       }
-       mutex_unlock(&group->device_lock);
+       fd_install(ret, filep);
 
        return ret;
 }
index 9e8e004bb1c38d809c2af43b9d42c053db3a41a2..eec2f11809ff2463d2a714224925af9c679fead1 100644 (file)
 #include <linux/file.h>
 #include <linux/highmem.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/kthread.h>
 #include <linux/cgroup.h>
 #include <linux/module.h>
+#include <linux/sort.h>
 
 #include "vhost.h"
 
+static ushort max_mem_regions = 64;
+module_param(max_mem_regions, ushort, 0444);
+MODULE_PARM_DESC(max_mem_regions,
+       "Maximum number of memory regions in memory map. (default: 64)");
+
 enum {
-       VHOST_MEMORY_MAX_NREGIONS = 64,
        VHOST_MEMORY_F_LOG = 0x1,
 };
 
@@ -543,7 +549,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
                fput(dev->log_file);
        dev->log_file = NULL;
        /* No one will access memory at this point */
-       kfree(dev->memory);
+       kvfree(dev->memory);
        dev->memory = NULL;
        WARN_ON(!list_empty(&dev->work_list));
        if (dev->worker) {
@@ -663,6 +669,25 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq)
 }
 EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
 
+static int vhost_memory_reg_sort_cmp(const void *p1, const void *p2)
+{
+       const struct vhost_memory_region *r1 = p1, *r2 = p2;
+       if (r1->guest_phys_addr < r2->guest_phys_addr)
+               return 1;
+       if (r1->guest_phys_addr > r2->guest_phys_addr)
+               return -1;
+       return 0;
+}
+
+static void *vhost_kvzalloc(unsigned long size)
+{
+       void *n = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+
+       if (!n)
+               n = vzalloc(size);
+       return n;
+}
+
 static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
 {
        struct vhost_memory mem, *newmem, *oldmem;
@@ -673,21 +698,23 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
                return -EFAULT;
        if (mem.padding)
                return -EOPNOTSUPP;
-       if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
+       if (mem.nregions > max_mem_regions)
                return -E2BIG;
-       newmem = kmalloc(size + mem.nregions * sizeof *m->regions, GFP_KERNEL);
+       newmem = vhost_kvzalloc(size + mem.nregions * sizeof(*m->regions));
        if (!newmem)
                return -ENOMEM;
 
        memcpy(newmem, &mem, size);
        if (copy_from_user(newmem->regions, m->regions,
                           mem.nregions * sizeof *m->regions)) {
-               kfree(newmem);
+               kvfree(newmem);
                return -EFAULT;
        }
+       sort(newmem->regions, newmem->nregions, sizeof(*newmem->regions),
+               vhost_memory_reg_sort_cmp, NULL);
 
        if (!memory_access_ok(d, newmem, 0)) {
-               kfree(newmem);
+               kvfree(newmem);
                return -EFAULT;
        }
        oldmem = d->memory;
@@ -699,7 +726,7 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
                d->vqs[i]->memory = newmem;
                mutex_unlock(&d->vqs[i]->mutex);
        }
-       kfree(oldmem);
+       kvfree(oldmem);
        return 0;
 }
 
@@ -965,6 +992,7 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
                }
                if (eventfp != d->log_file) {
                        filep = d->log_file;
+                       d->log_file = eventfp;
                        ctx = d->log_ctx;
                        d->log_ctx = eventfp ?
                                eventfd_ctx_fileget(eventfp) : NULL;
@@ -992,17 +1020,22 @@ EXPORT_SYMBOL_GPL(vhost_dev_ioctl);
 static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
                                                     __u64 addr, __u32 len)
 {
-       struct vhost_memory_region *reg;
-       int i;
+       const struct vhost_memory_region *reg;
+       int start = 0, end = mem->nregions;
 
-       /* linear search is not brilliant, but we really have on the order of 6
-        * regions in practice */
-       for (i = 0; i < mem->nregions; ++i) {
-               reg = mem->regions + i;
-               if (reg->guest_phys_addr <= addr &&
-                   reg->guest_phys_addr + reg->memory_size - 1 >= addr)
-                       return reg;
+       while (start < end) {
+               int slot = start + (end - start) / 2;
+               reg = mem->regions + slot;
+               if (addr >= reg->guest_phys_addr)
+                       end = slot;
+               else
+                       start = slot + 1;
        }
+
+       reg = mem->regions + start;
+       if (addr >= reg->guest_phys_addr &&
+               reg->guest_phys_addr + reg->memory_size > addr)
+               return reg;
        return NULL;
 }
 
index 8bf495ffb020789811358eef574b6aba446cb141..e0606c01e8ac7166d88d2ad20028c166ebef625e 100644 (file)
@@ -22,9 +22,7 @@ source "drivers/gpu/vga/Kconfig"
 source "drivers/gpu/host1x/Kconfig"
 source "drivers/gpu/ipu-v3/Kconfig"
 
-menu "Direct Rendering Manager"
 source "drivers/gpu/drm/Kconfig"
-endmenu
 
 menu "Frame buffer Devices"
 source "drivers/video/fbdev/Kconfig"
index 658c34bb9076f813058dfb03a47907ca48c6eb0a..1aaf89300621abc811f57f549c25b9a540a21d99 100644 (file)
@@ -1306,10 +1306,11 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
        int y;
        int c = scr_readw((u16 *) vc->vc_pos);
 
+       ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
+
        if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
                return;
 
-       ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
        if (vc->vc_cursor_type & 0x10)
                fbcon_del_cursor_timer(info);
        else
index 2d98de535e0f7374804474c58de752ffb2848aa4..f888561568d91735a3a765a772630e8b2be0a54a 100644 (file)
@@ -298,7 +298,7 @@ config FB_ARMCLCD
 
 # Helper logic selected only by the ARM Versatile platform family.
 config PLAT_VERSATILE_CLCD
-       def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
+       def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_INTEGRATOR
        depends on ARM
        depends on FB_ARMCLCD && FB=y
 
index 928ee639c0c19ba3a2346737c41b44f38e82c0b5..bf407b6ba15ca0002166a0704124eeda0fb2052e 100644 (file)
@@ -60,6 +60,8 @@ omapdss_of_get_next_port(const struct device_node *parent,
                        }
                        prev = port;
                } while (of_node_cmp(port->name, "port") != 0);
+
+               of_node_put(ports);
        }
 
        return port;
@@ -94,7 +96,7 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port)
        if (!port)
                return NULL;
 
-       np = of_get_next_parent(port);
+       np = of_get_parent(port);
 
        for (i = 0; i < 2 && np; ++i) {
                struct property *prop;
index 86bd457d039d2ad9a85e82d3f26a3630e3134da7..50bce45e7f3d47d78163058eff366b32d4f56180 100644 (file)
@@ -653,7 +653,7 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev)
                goto err_free_dma;
        }
 
-       ret = clk_enable(priv->clk);
+       ret = clk_prepare_enable(priv->clk);
        if (ret < 0) {
                dev_err(dev, "failed to enable clock\n");
                goto err_misc_deregister;
@@ -685,7 +685,7 @@ err_misc_deregister:
        misc_deregister(&priv->misc_dev);
 
 err_disable_clk:
-       clk_disable(priv->clk);
+       clk_disable_unprepare(priv->clk);
 
        return ret;
 }
index 111c2d1911d32ea38e86b11c0af753133ccfab05..b5102aa6090d111e25727f78422c8cbc183f086a 100644 (file)
@@ -44,11 +44,9 @@ int of_get_videomode(struct device_node *np, struct videomode *vm,
                index = disp->native_mode;
 
        ret = videomode_from_timings(disp, vm, index);
-       if (ret)
-               return ret;
 
        display_timings_release(disp);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(of_get_videomode);
index 60e2a16775637b778a8faeb8f2b3f84810a88716..c96944b59856c10c7d28c189b5ff86dbe4b3c932 100644 (file)
@@ -313,6 +313,7 @@ err_init_vq:
 static void virtinput_remove(struct virtio_device *vdev)
 {
        struct virtio_input *vi = vdev->priv;
+       void *buf;
        unsigned long flags;
 
        spin_lock_irqsave(&vi->lock, flags);
@@ -320,6 +321,9 @@ static void virtinput_remove(struct virtio_device *vdev)
        spin_unlock_irqrestore(&vi->lock, flags);
 
        input_unregister_device(vi->idev);
+       vdev->config->reset(vdev);
+       while ((buf = virtqueue_detach_unused_buf(vi->sts)) != NULL)
+               kfree(buf);
        vdev->config->del_vqs(vdev);
        kfree(vi);
 }
index fd933695f2328f29c2493ee751f22230ec68cbb1..bf4a23c7c5918f6849e764a8376c3608cc591933 100644 (file)
@@ -472,7 +472,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
 }
 
 /*
- * We avoid multiple worker processes conflicting via the balloon mutex.
+ * As this is a work item it is guaranteed to run as a single instance only.
  * We may of course race updates of the target counts (which are protected
  * by the balloon lock), or with changes to the Xen hard limit, but we will
  * recover from these in time.
@@ -482,9 +482,10 @@ static void balloon_process(struct work_struct *work)
        enum bp_state state = BP_DONE;
        long credit;
 
-       mutex_lock(&balloon_mutex);
 
        do {
+               mutex_lock(&balloon_mutex);
+
                credit = current_credit();
 
                if (credit > 0) {
@@ -499,17 +500,15 @@ static void balloon_process(struct work_struct *work)
 
                state = update_schedule(state);
 
-#ifndef CONFIG_PREEMPT
-               if (need_resched())
-                       schedule();
-#endif
+               mutex_unlock(&balloon_mutex);
+
+               cond_resched();
+
        } while (credit && state == BP_DONE);
 
        /* Schedule more work if there is some still to be done. */
        if (state == BP_EAGAIN)
                schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ);
-
-       mutex_unlock(&balloon_mutex);
 }
 
 /* Resets the Xen limit, sets new target, and kicks off processing. */
index 67b9163db7185402b0ff3811c5363c1a1022e2c7..0dbb222daaf1c694b1f073f3e206f755f5f77cc6 100644 (file)
@@ -568,12 +568,14 @@ static int gntdev_release(struct inode *inode, struct file *flip)
 
        pr_debug("priv %p\n", priv);
 
+       mutex_lock(&priv->lock);
        while (!list_empty(&priv->maps)) {
                map = list_entry(priv->maps.next, struct grant_map, next);
                list_del(&map->next);
                gntdev_put_map(NULL /* already removed */, map);
        }
        WARN_ON(!list_empty(&priv->freeable_maps));
+       mutex_unlock(&priv->lock);
 
        if (use_ptemod)
                mmu_notifier_unregister(&priv->mn, priv->mm);
index 9ad327238ba931243967455b5790916dc6b184f1..e30353575d5da11f75e8c927ba53945a23b73d76 100644 (file)
@@ -814,8 +814,10 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr)
 
        rv = xenbus_unmap_ring(dev, node->handles, node->nr_handles,
                               addrs);
-       if (!rv)
+       if (!rv) {
                vunmap(vaddr);
+               free_xenballooned_pages(node->nr_handles, node->hvm.pages);
+       }
        else
                WARN(1, "Leaking %p, size %u page(s)\n", vaddr,
                     node->nr_handles);
index 862fbc206755511a6bd3a02eeaa525e992c545bc..564a7de17d99831083c46bc19fd859d40a5d51a2 100644 (file)
@@ -378,7 +378,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
 
        ret = btrfs_kobj_add_device(tgt_device->fs_devices, tgt_device);
        if (ret)
-               btrfs_error(root->fs_info, ret, "kobj add dev failed");
+               btrfs_err(root->fs_info, "kobj add dev failed %d\n", ret);
 
        printk_in_rcu(KERN_INFO
                      "BTRFS: dev_replace from %s (devid %llu) to %s started\n",
index a9aadb2ad5254cfe98d36a6eed1f12d4ae5e7925..f556c3732c2c16e22e0bcbd35f9ee1277179be5b 100644 (file)
@@ -2842,6 +2842,7 @@ int open_ctree(struct super_block *sb,
            !extent_buffer_uptodate(chunk_root->node)) {
                printk(KERN_ERR "BTRFS: failed to read chunk root on %s\n",
                       sb->s_id);
+               chunk_root->node = NULL;
                goto fail_tree_roots;
        }
        btrfs_set_root_node(&chunk_root->root_item, chunk_root->node);
@@ -2879,7 +2880,7 @@ retry_root_backup:
            !extent_buffer_uptodate(tree_root->node)) {
                printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n",
                       sb->s_id);
-
+               tree_root->node = NULL;
                goto recovery_tree_root;
        }
 
index 171312d51799e358843216c945a18dee6d3a8790..07204bf601edac25ad2757bbd7c85961eeabc56c 100644 (file)
@@ -4227,6 +4227,24 @@ out:
        space_info->chunk_alloc = 0;
        spin_unlock(&space_info->lock);
        mutex_unlock(&fs_info->chunk_mutex);
+       /*
+        * When we allocate a new chunk we reserve space in the chunk block
+        * reserve to make sure we can COW nodes/leafs in the chunk tree or
+        * add new nodes/leafs to it if we end up needing to do it when
+        * inserting the chunk item and updating device items as part of the
+        * second phase of chunk allocation, performed by
+        * btrfs_finish_chunk_alloc(). So make sure we don't accumulate a
+        * large number of new block groups to create in our transaction
+        * handle's new_bgs list to avoid exhausting the chunk block reserve
+        * in extreme cases - like having a single transaction create many new
+        * block groups when starting to write out the free space caches of all
+        * the block groups that were made dirty during the lifetime of the
+        * transaction.
+        */
+       if (trans->chunk_bytes_reserved >= (2 * 1024 * 1024ull)) {
+               btrfs_create_pending_block_groups(trans, trans->root);
+               btrfs_trans_release_chunk_metadata(trans);
+       }
        return ret;
 }
 
index e9ace099162ce14d73d04523962465ee163b30c7..8a820295657686d634e3a5ded2ee21b5dcefc026 100644 (file)
@@ -1651,6 +1651,11 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info,
                                /* Exclusive -> exclusive, nothing changed */
                        }
                }
+
+               /* For exclusive extent, free its reserved bytes too */
+               if (nr_old_roots == 0 && nr_new_roots == 1 &&
+                   cur_new_count == nr_new_roots)
+                       qg->reserved -= num_bytes;
                if (dirty)
                        qgroup_dirty(fs_info, qg);
        }
index 51e0f0d0053e52c965c4ebed464fc4a761523a67..f5021fcb154e3bfa3773a79d94ee4750be48ca0d 100644 (file)
@@ -2152,7 +2152,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        kmem_cache_free(btrfs_trans_handle_cachep, trans);
 
-       if (current != root->fs_info->transaction_kthread)
+       if (current != root->fs_info->transaction_kthread &&
+           current != root->fs_info->cleaner_kthread)
                btrfs_run_delayed_iputs(root);
 
        return ret;
index dc10c9dd36c1a2ac6264ed21d3248e5f62f1e330..ddd5e94712904501db729c51b59de72cd88ddb5a 100644 (file)
@@ -1506,7 +1506,6 @@ static int __mark_caps_flushing(struct inode *inode,
 
        swap(cf, ci->i_prealloc_cap_flush);
        cf->caps = flushing;
-       cf->kick = false;
 
        spin_lock(&mdsc->cap_dirty_lock);
        list_del_init(&ci->i_dirty_item);
@@ -2123,8 +2122,7 @@ static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc,
 
 static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
                                struct ceph_mds_session *session,
-                               struct ceph_inode_info *ci,
-                               bool kick_all)
+                               struct ceph_inode_info *ci)
 {
        struct inode *inode = &ci->vfs_inode;
        struct ceph_cap *cap;
@@ -2150,9 +2148,7 @@ static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
 
                for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) {
                        cf = rb_entry(n, struct ceph_cap_flush, i_node);
-                       if (cf->tid < first_tid)
-                               continue;
-                       if (kick_all || cf->kick)
+                       if (cf->tid >= first_tid)
                                break;
                }
                if (!n) {
@@ -2161,7 +2157,6 @@ static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
                }
 
                cf = rb_entry(n, struct ceph_cap_flush, i_node);
-               cf->kick = false;
 
                first_tid = cf->tid + 1;
 
@@ -2181,8 +2176,6 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
 {
        struct ceph_inode_info *ci;
        struct ceph_cap *cap;
-       struct ceph_cap_flush *cf;
-       struct rb_node *n;
 
        dout("early_kick_flushing_caps mds%d\n", session->s_mds);
        list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
@@ -2205,16 +2198,11 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
                if ((cap->issued & ci->i_flushing_caps) !=
                    ci->i_flushing_caps) {
                        spin_unlock(&ci->i_ceph_lock);
-                       if (!__kick_flushing_caps(mdsc, session, ci, true))
+                       if (!__kick_flushing_caps(mdsc, session, ci))
                                continue;
                        spin_lock(&ci->i_ceph_lock);
                }
 
-               for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) {
-                       cf = rb_entry(n, struct ceph_cap_flush, i_node);
-                       cf->kick = true;
-               }
-
                spin_unlock(&ci->i_ceph_lock);
        }
 }
@@ -2228,7 +2216,7 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
 
        dout("kick_flushing_caps mds%d\n", session->s_mds);
        list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
-               int delayed = __kick_flushing_caps(mdsc, session, ci, false);
+               int delayed = __kick_flushing_caps(mdsc, session, ci);
                if (delayed) {
                        spin_lock(&ci->i_ceph_lock);
                        __cap_delay_requeue(mdsc, ci);
@@ -2261,7 +2249,7 @@ static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
 
                spin_unlock(&ci->i_ceph_lock);
 
-               delayed = __kick_flushing_caps(mdsc, session, ci, true);
+               delayed = __kick_flushing_caps(mdsc, session, ci);
                if (delayed) {
                        spin_lock(&ci->i_ceph_lock);
                        __cap_delay_requeue(mdsc, ci);
index 4347039ecc183d538c23f32019e5213da2ebf2f4..6706bde9ad1b1e16e6a283a83ea93c4f58b6b2aa 100644 (file)
@@ -287,7 +287,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
                return 0;
 
        spin_lock(&ctx->flc_lock);
-       list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
+       list_for_each_entry(lock, &ctx->flc_posix, fl_list) {
                ++seen_fcntl;
                if (seen_fcntl > num_fcntl_locks) {
                        err = -ENOSPC;
index 860cc016e70d4ff463c1f7845fc648eaf58269c4..2f2460d23a0600f8f9bf2e1cc4fe3b2286684356 100644 (file)
@@ -189,7 +189,6 @@ static inline void ceph_put_cap_snap(struct ceph_cap_snap *capsnap)
 struct ceph_cap_flush {
        u64 tid;
        int caps;
-       bool kick;
        struct rb_node g_node; // global
        union {
                struct rb_node i_node; // inode
index c3e21ccfc358b2da1170c15f09a5946afad0ff16..a7f77e1fa18c25e62e8de5f809389d041e59266e 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -319,6 +319,12 @@ static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh,
  * @vma: The virtual memory area where the fault occurred
  * @vmf: The description of the fault
  * @get_block: The filesystem method used to translate file offsets to blocks
+ * @complete_unwritten: The filesystem method used to convert unwritten blocks
+ *     to written so the data written to them is exposed. This is required for
+ *     required by write faults for filesystems that will return unwritten
+ *     extent mappings from @get_block, but it is optional for reads as
+ *     dax_insert_mapping() will always zero unwritten blocks. If the fs does
+ *     not support unwritten extents, the it should pass NULL.
  *
  * When a page fault occurs, filesystems may call this helper in their
  * fault handler for DAX files. __dax_fault() assumes the caller has done all
@@ -437,8 +443,12 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
         * as for normal BH based IO completions.
         */
        error = dax_insert_mapping(inode, &bh, vma, vmf);
-       if (buffer_unwritten(&bh))
-               complete_unwritten(&bh, !error);
+       if (buffer_unwritten(&bh)) {
+               if (complete_unwritten)
+                       complete_unwritten(&bh, !error);
+               else
+                       WARN_ON_ONCE(!(vmf->flags & FAULT_FLAG_WRITE));
+       }
 
  out:
        if (error == -ENOMEM)
index 5c8ea15e73a53b6b6dbe3e9660973d2eda9c7800..9b5fe503f6cb6c8d76044bb8272084fdb0474c9b 100644 (file)
@@ -3442,22 +3442,15 @@ void __init vfs_caches_init_early(void)
        inode_init_early();
 }
 
-void __init vfs_caches_init(unsigned long mempages)
+void __init vfs_caches_init(void)
 {
-       unsigned long reserve;
-
-       /* Base hash sizes on available memory, with a reserve equal to
-           150% of current kernel size */
-
-       reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);
-       mempages -= reserve;
-
        names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
        dcache_init();
        inode_init();
-       files_init(mempages);
+       files_init();
+       files_maxfiles_init();
        mnt_init();
        bdev_cache_init();
        chrdev_init();
index 9bedfa8dd3a5305d1407ce04c5fa3319a6882cd3..f71e19a9dd3c18fc6ee7b3bcb4f3da9c8b8c3d4c 100644 (file)
@@ -2072,8 +2072,6 @@ static int f2fs_set_data_page_dirty(struct page *page)
                return 1;
        }
 
-       mark_inode_dirty(inode);
-
        if (!PageDirty(page)) {
                __set_page_dirty_nobuffers(page);
                update_dirty_page(inode, page);
index ada2a3dd701ad5eb22add128a0d5e89ebb98383f..b0f38c3b37f4d5577551e6d517e801a6f644ac09 100644 (file)
@@ -1331,12 +1331,13 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
        if (ret)
                return ret;
 
-       if (f2fs_is_atomic_file(inode))
+       if (f2fs_is_atomic_file(inode)) {
+               clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
                commit_inmem_pages(inode, false);
+       }
 
        ret = f2fs_sync_file(filp, 0, LONG_MAX, 0);
        mnt_drop_write_file(filp);
-       clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
        return ret;
 }
 
@@ -1387,8 +1388,8 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp)
        f2fs_balance_fs(F2FS_I_SB(inode));
 
        if (f2fs_is_atomic_file(inode)) {
-               commit_inmem_pages(inode, false);
                clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+               commit_inmem_pages(inode, false);
        }
 
        if (f2fs_is_volatile_file(inode))
index e1e73617d13b6cb5e1fca434e4ab823dfa534eca..22fb5ef37966210cb50f5b8679b7c661803128f9 100644 (file)
@@ -556,27 +556,39 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)
        if (!fio.encrypted_page)
                goto put_out;
 
-       f2fs_submit_page_bio(&fio);
+       err = f2fs_submit_page_bio(&fio);
+       if (err)
+               goto put_page_out;
+
+       /* write page */
+       lock_page(fio.encrypted_page);
+
+       if (unlikely(!PageUptodate(fio.encrypted_page)))
+               goto put_page_out;
+       if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi)))
+               goto put_page_out;
+
+       set_page_dirty(fio.encrypted_page);
+       f2fs_wait_on_page_writeback(fio.encrypted_page, META);
+       if (clear_page_dirty_for_io(fio.encrypted_page))
+               dec_page_count(fio.sbi, F2FS_DIRTY_META);
+
+       set_page_writeback(fio.encrypted_page);
 
        /* allocate block address */
        f2fs_wait_on_page_writeback(dn.node_page, NODE);
-
        allocate_data_block(fio.sbi, NULL, fio.blk_addr,
                                        &fio.blk_addr, &sum, CURSEG_COLD_DATA);
-       dn.data_blkaddr = fio.blk_addr;
-
-       /* write page */
-       lock_page(fio.encrypted_page);
-       set_page_writeback(fio.encrypted_page);
        fio.rw = WRITE_SYNC;
        f2fs_submit_page_mbio(&fio);
 
+       dn.data_blkaddr = fio.blk_addr;
        set_data_blkaddr(&dn);
        f2fs_update_extent_cache(&dn);
        set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE);
        if (page->index == 0)
                set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
-
+put_page_out:
        f2fs_put_page(fio.encrypted_page, 1);
 put_out:
        f2fs_put_dnode(&dn);
@@ -605,8 +617,8 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type)
                        .page = page,
                        .encrypted_page = NULL,
                };
+               set_page_dirty(page);
                f2fs_wait_on_page_writeback(page, DATA);
-
                if (clear_page_dirty_for_io(page))
                        inode_dec_dirty_pages(inode);
                set_cold_data(page);
index 38e75fb1e48812b38d477a13a53f0469fb95bbd3..a13ffcc329923b85f6dee0064e56681bf8a1269c 100644 (file)
@@ -141,6 +141,8 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
        kunmap_atomic(dst_addr);
        SetPageUptodate(page);
 no_update:
+       set_page_dirty(page);
+
        /* clear dirty state */
        dirty = clear_page_dirty_for_io(page);
 
index 1eb343768781f3c4c89e0f6ecc2694d9a4c61c75..61b97f9cb9f657961d7ce12a490d55ece03e18a4 100644 (file)
@@ -257,6 +257,7 @@ void commit_inmem_pages(struct inode *inode, bool abort)
                if (!abort) {
                        lock_page(cur->page);
                        if (cur->page->mapping == inode->i_mapping) {
+                               set_page_dirty(cur->page);
                                f2fs_wait_on_page_writeback(cur->page, DATA);
                                if (clear_page_dirty_for_io(cur->page))
                                        inode_dec_dirty_pages(inode);
index 7f9d407c759596f950335bd418ab0226f4a629f8..ad17e05ebf95f07888b15f2b09a7b37ac89b9710 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/hardirq.h>
 #include <linux/task_work.h>
 #include <linux/ima.h>
+#include <linux/swap.h>
 
 #include <linux/atomic.h>
 
@@ -308,19 +309,24 @@ void put_filp(struct file *file)
        }
 }
 
-void __init files_init(unsigned long mempages)
+void __init files_init(void)
 { 
-       unsigned long n;
-
        filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
                        SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+       percpu_counter_init(&nr_files, 0, GFP_KERNEL);
+}
 
-       /*
-        * One file with associated inode and dcache is very roughly 1K.
-        * Per default don't use more than 10% of our memory for files. 
-        */ 
+/*
+ * One file with associated inode and dcache is very roughly 1K. Per default
+ * do not use more than 10% of our memory for files.
+ */
+void __init files_maxfiles_init(void)
+{
+       unsigned long n;
+       unsigned long memreserve = (totalram_pages - nr_free_pages()) * 3/2;
+
+       memreserve = min(memreserve, totalram_pages - 1);
+       n = ((totalram_pages - memreserve) * (PAGE_SIZE / 1024)) / 10;
 
-       n = (mempages * (PAGE_SIZE / 1024)) / 10;
        files_stat.max_files = max_t(unsigned long, n, NR_FILE);
-       percpu_counter_init(&nr_files, 0, GFP_KERNEL);
 } 
index f0520bcf209442914eff0ed60d380fb3d2c66402..518c6294bf6c0ef965e9f56baa4e11d2eccc0165 100644 (file)
@@ -702,6 +702,7 @@ void wbc_account_io(struct writeback_control *wbc, struct page *page,
        else
                wbc->wb_tcand_bytes -= min(bytes, wbc->wb_tcand_bytes);
 }
+EXPORT_SYMBOL_GPL(wbc_account_io);
 
 /**
  * inode_congested - test whether an inode is congested
index 80cc1b35d46043c16bc456e0cadf61e76c281d52..ebb5e37455a07acd86f5fbf1b76d474e99b937fb 100644 (file)
@@ -2246,7 +2246,15 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
 
                        err = -EINVAL;
                        if (old) {
-                               struct fuse_dev *fud = fuse_get_dev(old);
+                               struct fuse_dev *fud = NULL;
+
+                               /*
+                                * Check against file->f_op because CUSE
+                                * uses the same ioctl handler.
+                                */
+                               if (old->f_op == file->f_op &&
+                                   old->f_cred->user_ns == file->f_cred->user_ns)
+                                       fud = fuse_get_dev(old);
 
                                if (fud) {
                                        mutex_lock(&fuse_mutex);
index 0cf74df68617b8738342a5f7be7992ccc596bf0a..973c24ce59ad3ef1b62ff3ce00113d7d85cedb68 100644 (file)
@@ -1010,6 +1010,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
        inode = hugetlbfs_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0);
        if (!inode)
                goto out_dentry;
+       if (creat_flags == HUGETLB_SHMFS_INODE)
+               inode->i_flags |= S_PRIVATE;
 
        file = ERR_PTR(-ENOMEM);
        if (hugetlb_reserve_pages(inode, 0,
index ae4e4c18b2ac0b2c366f893f7ffa4d898446c0f7..1c2105ed20c5ef4fb390878fb5442943ceec29ae 100644 (file)
@@ -879,7 +879,7 @@ static inline int may_follow_link(struct nameidata *nd)
                return 0;
 
        /* Allowed if parent directory not sticky and world-writable. */
-       parent = nd->path.dentry->d_inode;
+       parent = nd->inode;
        if ((parent->i_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH))
                return 0;
 
@@ -1954,8 +1954,13 @@ OK:
                                continue;
                        }
                }
-               if (unlikely(!d_can_lookup(nd->path.dentry)))
+               if (unlikely(!d_can_lookup(nd->path.dentry))) {
+                       if (nd->flags & LOOKUP_RCU) {
+                               if (unlazy_walk(nd, NULL, 0))
+                                       return -ECHILD;
+                       }
                        return -ENOTDIR;
+               }
        }
 }
 
index c7cb8a526c05fbaa5ba18934cd04eda1eb2a6e60..2b8aa15fd6dfa755368ddf21136eaab5192f1e28 100644 (file)
@@ -1361,6 +1361,36 @@ enum umount_tree_flags {
        UMOUNT_PROPAGATE = 2,
        UMOUNT_CONNECTED = 4,
 };
+
+static bool disconnect_mount(struct mount *mnt, enum umount_tree_flags how)
+{
+       /* Leaving mounts connected is only valid for lazy umounts */
+       if (how & UMOUNT_SYNC)
+               return true;
+
+       /* A mount without a parent has nothing to be connected to */
+       if (!mnt_has_parent(mnt))
+               return true;
+
+       /* Because the reference counting rules change when mounts are
+        * unmounted and connected, umounted mounts may not be
+        * connected to mounted mounts.
+        */
+       if (!(mnt->mnt_parent->mnt.mnt_flags & MNT_UMOUNT))
+               return true;
+
+       /* Has it been requested that the mount remain connected? */
+       if (how & UMOUNT_CONNECTED)
+               return false;
+
+       /* Is the mount locked such that it needs to remain connected? */
+       if (IS_MNT_LOCKED(mnt))
+               return false;
+
+       /* By default disconnect the mount */
+       return true;
+}
+
 /*
  * mount_lock must be held
  * namespace_sem must be held for write
@@ -1398,10 +1428,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
                if (how & UMOUNT_SYNC)
                        p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
 
-               disconnect = !(((how & UMOUNT_CONNECTED) &&
-                               mnt_has_parent(p) &&
-                               (p->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) ||
-                              IS_MNT_LOCKED_AND_LAZY(p));
+               disconnect = disconnect_mount(p, how);
 
                pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,
                                 disconnect ? &unmounted : NULL);
@@ -1538,11 +1565,8 @@ void __detach_mounts(struct dentry *dentry)
        while (!hlist_empty(&mp->m_list)) {
                mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
                if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
-                       struct mount *p, *tmp;
-                       list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts,  mnt_child) {
-                               hlist_add_head(&p->mnt_umount.s_list, &unmounted);
-                               umount_mnt(p);
-                       }
+                       hlist_add_head(&mnt->mnt_umount.s_list, &unmounted);
+                       umount_mnt(mnt);
                }
                else umount_tree(mnt, UMOUNT_CONNECTED);
        }
index ecebb406cc1aec554ce780f2c3680eddc351e8da..4a90c9bb31357305ed6f38166bb0e9afabaae953 100644 (file)
@@ -775,7 +775,7 @@ static int nfs_init_server(struct nfs_server *server,
        server->options = data->options;
        server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
                NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
-               NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME|NFS_CAP_CHANGE_ATTR;
+               NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
 
        if (data->rsize)
                server->rsize = nfs_block_size(data->rsize, NULL);
index c12951b9551eab8b0394ed2aa218cf15ce6f2c39..b3289d701eea21623f4081fee1b2807e3e2f4b3a 100644 (file)
@@ -1852,7 +1852,7 @@ ff_layout_mirror_prepare_stats(struct nfs42_layoutstat_args *args,
        struct nfs42_layoutstat_devinfo *devinfo;
        int i;
 
-       for (i = 0; i <= FF_LAYOUT_MIRROR_COUNT(pls); i++) {
+       for (i = 0; i < FF_LAYOUT_MIRROR_COUNT(pls); i++) {
                if (*dev_count >= dev_limit)
                        break;
                mirror = FF_LAYOUT_COMP(pls, i);
index b77b328a06d74f0124d2a65b51fac0fc21fbd692..0adc7d245b3dd838e32371920e23d9dda5071ee0 100644 (file)
@@ -442,8 +442,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
                if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
                        inode->i_version = fattr->change_attr;
-               else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR))
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
+               else
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
+                               | NFS_INO_REVAL_PAGECACHE);
                if (fattr->valid & NFS_ATTR_FATTR_SIZE)
                        inode->i_size = nfs_size_to_loff_t(fattr->size);
                else
@@ -1244,9 +1245,11 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
        if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
                cur_size = i_size_read(inode);
                new_isize = nfs_size_to_loff_t(fattr->size);
-               if (cur_size != new_isize && nfsi->nrequests == 0)
+               if (cur_size != new_isize)
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
        }
+       if (nfsi->nrequests != 0)
+               invalid &= ~NFS_INO_REVAL_PAGECACHE;
 
        /* Have any file permissions changed? */
        if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
@@ -1684,13 +1687,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        invalid |= NFS_INO_INVALID_ATTR
                                | NFS_INO_INVALID_DATA
                                | NFS_INO_INVALID_ACCESS
-                               | NFS_INO_INVALID_ACL
-                               | NFS_INO_REVAL_PAGECACHE;
+                               | NFS_INO_INVALID_ACL;
                        if (S_ISDIR(inode->i_mode))
                                nfs_force_lookup_revalidate(inode);
                        inode->i_version = fattr->change_attr;
                }
-       } else if (server->caps & NFS_CAP_CHANGE_ATTR)
+       } else
                nfsi->cache_validity |= save_cache_validity;
 
        if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
@@ -1717,7 +1719,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        if ((nfsi->nrequests == 0) || new_isize > cur_isize) {
                                i_size_write(inode, new_isize);
                                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
-                               invalid &= ~NFS_INO_REVAL_PAGECACHE;
                        }
                        dprintk("NFS: isize change on server for file %s/%ld "
                                        "(%Ld to %Ld)\n",
index 7e3c4604bea8a6e6e92906b6c2096adb6df5ca3f..9b372b845f6a6ff06a4a035e2f6799d7d29cd8f7 100644 (file)
@@ -296,6 +296,22 @@ extern struct rpc_procinfo nfs4_procedures[];
 
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
 extern struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags);
+static inline struct nfs4_label *
+nfs4_label_copy(struct nfs4_label *dst, struct nfs4_label *src)
+{
+       if (!dst || !src)
+               return NULL;
+
+       if (src->len > NFS4_MAXLABELLEN)
+               return NULL;
+
+       dst->lfs = src->lfs;
+       dst->pi = src->pi;
+       dst->len = src->len;
+       memcpy(dst->label, src->label, src->len);
+
+       return dst;
+}
 static inline void nfs4_label_free(struct nfs4_label *label)
 {
        if (label) {
@@ -316,6 +332,11 @@ static inline void nfs4_label_free(void *label) {}
 static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi)
 {
 }
+static inline struct nfs4_label *
+nfs4_label_copy(struct nfs4_label *dst, struct nfs4_label *src)
+{
+       return NULL;
+}
 #endif /* CONFIG_NFS_V4_SECURITY_LABEL */
 
 /* proc.c */
index f486b80f927ab7204159852a9740900a6c73aec6..d731bbf974aaf1d4bf695c2cb57a99cc586e0258 100644 (file)
@@ -135,7 +135,7 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
        return err;
 }
 
-loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
+static loff_t _nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
 {
        struct inode *inode = file_inode(filep);
        struct nfs42_seek_args args = {
@@ -171,6 +171,23 @@ loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
        return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes);
 }
 
+loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
+{
+       struct nfs_server *server = NFS_SERVER(file_inode(filep));
+       struct nfs4_exception exception = { };
+       int err;
+
+       do {
+               err = _nfs42_proc_llseek(filep, offset, whence);
+               if (err == -ENOTSUPP)
+                       return -EOPNOTSUPP;
+               err = nfs4_handle_exception(server, err, &exception);
+       } while (exception.retry);
+
+       return err;
+}
+
+
 static void
 nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
 {
index 8bee93469617eeddffa0e56038deed9051221420..3acb1eb72930c40828bab90aeb27a3918f71138d 100644 (file)
@@ -467,7 +467,10 @@ static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
 
 static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
 {
-       do_renew_lease(server->nfs_client, timestamp);
+       struct nfs_client *clp = server->nfs_client;
+
+       if (!nfs4_has_session(clp))
+               do_renew_lease(clp, timestamp);
 }
 
 struct nfs4_call_sync_data {
@@ -616,8 +619,7 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
                clp = session->clp;
                do_renew_lease(clp, res->sr_timestamp);
                /* Check sequence flags */
-               if (res->sr_status_flags != 0)
-                       nfs4_schedule_lease_recovery(clp);
+               nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
                nfs41_update_target_slotid(slot->table, slot, res);
                break;
        case 1:
@@ -910,6 +912,7 @@ struct nfs4_opendata {
        struct nfs_open_confirmres c_res;
        struct nfs4_string owner_name;
        struct nfs4_string group_name;
+       struct nfs4_label *a_label;
        struct nfs_fattr f_attr;
        struct nfs4_label *f_label;
        struct dentry *dir;
@@ -1013,6 +1016,10 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        if (IS_ERR(p->f_label))
                goto err_free_p;
 
+       p->a_label = nfs4_label_alloc(server, gfp_mask);
+       if (IS_ERR(p->a_label))
+               goto err_free_f;
+
        alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
        p->o_arg.seqid = alloc_seqid(&sp->so_seqid, gfp_mask);
        if (IS_ERR(p->o_arg.seqid))
@@ -1041,7 +1048,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        p->o_arg.server = server;
        p->o_arg.bitmask = nfs4_bitmask(server, label);
        p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
-       p->o_arg.label = label;
+       p->o_arg.label = nfs4_label_copy(p->a_label, label);
        p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
        switch (p->o_arg.claim) {
        case NFS4_OPEN_CLAIM_NULL:
@@ -1074,6 +1081,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        return p;
 
 err_free_label:
+       nfs4_label_free(p->a_label);
+err_free_f:
        nfs4_label_free(p->f_label);
 err_free_p:
        kfree(p);
@@ -1093,6 +1102,7 @@ static void nfs4_opendata_free(struct kref *kref)
                nfs4_put_open_state(p->state);
        nfs4_put_state_owner(p->owner);
 
+       nfs4_label_free(p->a_label);
        nfs4_label_free(p->f_label);
 
        dput(p->dir);
@@ -1198,12 +1208,15 @@ static bool nfs_need_update_open_stateid(struct nfs4_state *state,
 
 static void nfs_resync_open_stateid_locked(struct nfs4_state *state)
 {
+       if (!(state->n_wronly || state->n_rdonly || state->n_rdwr))
+               return;
        if (state->n_wronly)
                set_bit(NFS_O_WRONLY_STATE, &state->flags);
        if (state->n_rdonly)
                set_bit(NFS_O_RDONLY_STATE, &state->flags);
        if (state->n_rdwr)
                set_bit(NFS_O_RDWR_STATE, &state->flags);
+       set_bit(NFS_OPEN_STATE, &state->flags);
 }
 
 static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
@@ -7571,13 +7584,8 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
                goto out;
        }
        ret = rpc_wait_for_completion_task(task);
-       if (!ret) {
-               struct nfs4_sequence_res *res = task->tk_msg.rpc_resp;
-
-               if (task->tk_status == 0)
-                       nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
+       if (!ret)
                ret = task->tk_status;
-       }
        rpc_put_task(task);
 out:
        dprintk("<-- %s status=%d\n", __func__, ret);
@@ -7965,16 +7973,17 @@ static void nfs4_layoutreturn_release(void *calldata)
 {
        struct nfs4_layoutreturn *lrp = calldata;
        struct pnfs_layout_hdr *lo = lrp->args.layout;
+       LIST_HEAD(freeme);
 
        dprintk("--> %s\n", __func__);
        spin_lock(&lo->plh_inode->i_lock);
        if (lrp->res.lrs_present)
                pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
+       pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range);
        pnfs_clear_layoutreturn_waitbit(lo);
-       clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags);
-       rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
        lo->plh_block_lgets--;
        spin_unlock(&lo->plh_inode->i_lock);
+       pnfs_free_lseg_list(&freeme);
        pnfs_put_layout_hdr(lrp->args.layout);
        nfs_iput_and_deactive(lrp->inode);
        kfree(calldata);
@@ -8588,7 +8597,6 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
        .minor_version = 0,
        .init_caps = NFS_CAP_READDIRPLUS
                | NFS_CAP_ATOMIC_OPEN
-               | NFS_CAP_CHANGE_ATTR
                | NFS_CAP_POSIX_LOCK,
        .init_client = nfs40_init_client,
        .shutdown_client = nfs40_shutdown_client,
@@ -8614,7 +8622,6 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
        .minor_version = 1,
        .init_caps = NFS_CAP_READDIRPLUS
                | NFS_CAP_ATOMIC_OPEN
-               | NFS_CAP_CHANGE_ATTR
                | NFS_CAP_POSIX_LOCK
                | NFS_CAP_STATEID_NFSV41
                | NFS_CAP_ATOMIC_OPEN_V1,
@@ -8637,7 +8644,6 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
        .minor_version = 2,
        .init_caps = NFS_CAP_READDIRPLUS
                | NFS_CAP_ATOMIC_OPEN
-               | NFS_CAP_CHANGE_ATTR
                | NFS_CAP_POSIX_LOCK
                | NFS_CAP_STATEID_NFSV41
                | NFS_CAP_ATOMIC_OPEN_V1
index 605840dc89cf9e28c173659af201aab109f9328d..f2e2ad8944617f679a4a85934f6a276d3665229d 100644 (file)
@@ -2191,25 +2191,35 @@ static void nfs41_handle_server_reboot(struct nfs_client *clp)
        }
 }
 
-static void nfs41_handle_state_revoked(struct nfs_client *clp)
+static void nfs41_handle_all_state_revoked(struct nfs_client *clp)
 {
        nfs4_reset_all_state(clp);
        dprintk("%s: state revoked on server %s\n", __func__, clp->cl_hostname);
 }
 
+static void nfs41_handle_some_state_revoked(struct nfs_client *clp)
+{
+       nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
+       nfs4_schedule_state_manager(clp);
+
+       dprintk("%s: state revoked on server %s\n", __func__, clp->cl_hostname);
+}
+
 static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp)
 {
-       /* This will need to handle layouts too */
-       nfs_expire_all_delegations(clp);
+       /* FIXME: For now, we destroy all layouts. */
+       pnfs_destroy_all_layouts(clp);
+       /* FIXME: For now, we test all delegations+open state+locks. */
+       nfs41_handle_some_state_revoked(clp);
        dprintk("%s: Recallable state revoked on server %s!\n", __func__,
                        clp->cl_hostname);
 }
 
 static void nfs41_handle_backchannel_fault(struct nfs_client *clp)
 {
-       nfs_expire_all_delegations(clp);
-       if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0)
-               nfs4_schedule_state_manager(clp);
+       set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
+       nfs4_schedule_state_manager(clp);
+
        dprintk("%s: server %s declared a backchannel fault\n", __func__,
                        clp->cl_hostname);
 }
@@ -2231,10 +2241,11 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
 
        if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
                nfs41_handle_server_reboot(clp);
-       if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
-                           SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
+       if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED))
+               nfs41_handle_all_state_revoked(clp);
+       if (flags & (SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
                            SEQ4_STATUS_ADMIN_STATE_REVOKED))
-               nfs41_handle_state_revoked(clp);
+               nfs41_handle_some_state_revoked(clp);
        if (flags & SEQ4_STATUS_LEASE_MOVED)
                nfs4_schedule_lease_moved_recovery(clp);
        if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
index 1da68d3b1edabdb78c60527f502af5f40d6cf69b..4984bbe55ff1eed1623df2196bc0de0de41a4304 100644 (file)
@@ -1100,8 +1100,6 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
                mirror->pg_base = 0;
                mirror->pg_recoalesce = 0;
 
-               desc->pg_moreio = 0;
-
                while (!list_empty(&head)) {
                        struct nfs_page *req;
 
@@ -1109,8 +1107,11 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
                        nfs_list_remove_request(req);
                        if (__nfs_pageio_add_request(desc, req))
                                continue;
-                       if (desc->pg_error < 0)
+                       if (desc->pg_error < 0) {
+                               list_splice_tail(&head, &mirror->pg_list);
+                               mirror->pg_recoalesce = 1;
                                return 0;
+                       }
                        break;
                }
        } while (mirror->pg_recoalesce);
index 0ba9a02c95664960f8c0f46ea97249bd8653fe16..70bf706b10904e156affe9dd4bea2ec9a17776c5 100644 (file)
@@ -352,7 +352,7 @@ pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
 {
        struct pnfs_layout_segment *s;
 
-       if (!test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
+       if (!test_and_clear_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
                return false;
 
        list_for_each_entry(s, &lo->plh_segs, pls_list)
@@ -362,6 +362,18 @@ pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
        return true;
 }
 
+static bool
+pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
+{
+       if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
+               return false;
+       lo->plh_return_iomode = 0;
+       lo->plh_block_lgets++;
+       pnfs_get_layout_hdr(lo);
+       clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags);
+       return true;
+}
+
 static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg,
                struct pnfs_layout_hdr *lo, struct inode *inode)
 {
@@ -372,17 +384,16 @@ static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg,
        if (pnfs_layout_need_return(lo, lseg)) {
                nfs4_stateid stateid;
                enum pnfs_iomode iomode;
+               bool send;
 
                stateid = lo->plh_stateid;
                iomode = lo->plh_return_iomode;
-               /* decreased in pnfs_send_layoutreturn() */
-               lo->plh_block_lgets++;
-               lo->plh_return_iomode = 0;
+               send = pnfs_prepare_layoutreturn(lo);
                spin_unlock(&inode->i_lock);
-               pnfs_get_layout_hdr(lo);
-
-               /* Send an async layoutreturn so we dont deadlock */
-               pnfs_send_layoutreturn(lo, stateid, iomode, false);
+               if (send) {
+                       /* Send an async layoutreturn so we dont deadlock */
+                       pnfs_send_layoutreturn(lo, stateid, iomode, false);
+               }
        } else
                spin_unlock(&inode->i_lock);
 }
@@ -411,6 +422,10 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
                pnfs_layoutreturn_before_put_lseg(lseg, lo, inode);
 
        if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
+               if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) {
+                       spin_unlock(&inode->i_lock);
+                       return;
+               }
                pnfs_get_layout_hdr(lo);
                pnfs_layout_remove_lseg(lo, lseg);
                spin_unlock(&inode->i_lock);
@@ -451,6 +466,8 @@ pnfs_put_lseg_locked(struct pnfs_layout_segment *lseg)
                test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
        if (atomic_dec_and_test(&lseg->pls_refcount)) {
                struct pnfs_layout_hdr *lo = lseg->pls_layout;
+               if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags))
+                       return;
                pnfs_get_layout_hdr(lo);
                pnfs_layout_remove_lseg(lo, lseg);
                pnfs_free_lseg_async(lseg);
@@ -924,6 +941,7 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
        clear_bit_unlock(NFS_LAYOUT_RETURN, &lo->plh_flags);
        smp_mb__after_atomic();
        wake_up_bit(&lo->plh_flags, NFS_LAYOUT_RETURN);
+       rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
 }
 
 static int
@@ -978,6 +996,7 @@ _pnfs_return_layout(struct inode *ino)
        LIST_HEAD(tmp_list);
        nfs4_stateid stateid;
        int status = 0, empty;
+       bool send;
 
        dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino);
 
@@ -1007,17 +1026,18 @@ _pnfs_return_layout(struct inode *ino)
        /* Don't send a LAYOUTRETURN if list was initially empty */
        if (empty) {
                spin_unlock(&ino->i_lock);
-               pnfs_put_layout_hdr(lo);
                dprintk("NFS: %s no layout segments to return\n", __func__);
-               goto out;
+               goto out_put_layout_hdr;
        }
 
        set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
-       lo->plh_block_lgets++;
+       send = pnfs_prepare_layoutreturn(lo);
        spin_unlock(&ino->i_lock);
        pnfs_free_lseg_list(&tmp_list);
-
-       status = pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true);
+       if (send)
+               status = pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true);
+out_put_layout_hdr:
+       pnfs_put_layout_hdr(lo);
 out:
        dprintk("<-- %s status: %d\n", __func__, status);
        return status;
@@ -1097,13 +1117,9 @@ bool pnfs_roc(struct inode *ino)
 out_noroc:
        if (lo) {
                stateid = lo->plh_stateid;
-               layoutreturn =
-                       test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
-                                          &lo->plh_flags);
-               if (layoutreturn) {
-                       lo->plh_block_lgets++;
-                       pnfs_get_layout_hdr(lo);
-               }
+               if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
+                                          &lo->plh_flags))
+                       layoutreturn = pnfs_prepare_layoutreturn(lo);
        }
        spin_unlock(&ino->i_lock);
        if (layoutreturn) {
@@ -1146,15 +1162,18 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
        struct pnfs_layout_segment *lseg;
        nfs4_stateid stateid;
        u32 current_seqid;
-       bool found = false, layoutreturn = false;
+       bool layoutreturn = false;
 
        spin_lock(&ino->i_lock);
-       list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list)
-               if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
-                       rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
-                       found = true;
-                       goto out;
-               }
+       list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list) {
+               if (!test_bit(NFS_LSEG_ROC, &lseg->pls_flags))
+                       continue;
+               if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags))
+                       continue;
+               rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
+               spin_unlock(&ino->i_lock);
+               return true;
+       }
        lo = nfsi->layout;
        current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
 
@@ -1162,23 +1181,19 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
         * a barrier, we choose the worst-case barrier.
         */
        *barrier = current_seqid + atomic_read(&lo->plh_outstanding);
-out:
-       if (!found) {
-               stateid = lo->plh_stateid;
-               layoutreturn =
-                       test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
-                                          &lo->plh_flags);
-               if (layoutreturn) {
-                       lo->plh_block_lgets++;
-                       pnfs_get_layout_hdr(lo);
-               }
-       }
+       stateid = lo->plh_stateid;
+       if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
+                                          &lo->plh_flags))
+               layoutreturn = pnfs_prepare_layoutreturn(lo);
+       if (test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
+               rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
+
        spin_unlock(&ino->i_lock);
        if (layoutreturn) {
-               rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
                pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, false);
+               return true;
        }
-       return found;
+       return false;
 }
 
 /*
@@ -1695,7 +1710,6 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
        spin_lock(&inode->i_lock);
        /* set failure bit so that pnfs path will be retried later */
        pnfs_layout_set_fail_bit(lo, iomode);
-       set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags);
        if (lo->plh_return_iomode == 0)
                lo->plh_return_iomode = range.iomode;
        else if (lo->plh_return_iomode != range.iomode)
@@ -2207,13 +2221,12 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
        if (ld->prepare_layoutcommit) {
                status = ld->prepare_layoutcommit(&data->args);
                if (status) {
+                       put_rpccred(data->cred);
                        spin_lock(&inode->i_lock);
                        set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags);
                        if (end_pos > nfsi->layout->plh_lwb)
                                nfsi->layout->plh_lwb = end_pos;
-                       spin_unlock(&inode->i_lock);
-                       put_rpccred(data->cred);
-                       goto clear_layoutcommitting;
+                       goto out_unlock;
                }
        }
 
index 65869ca9c851dbf4f0b289ca84865a018c2b6e57..75a35a1afa7944d4ac54bd94994cddf1fd05ab54 100644 (file)
@@ -1379,24 +1379,27 @@ static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
 {
        struct nfs_pgio_args *argp = &hdr->args;
        struct nfs_pgio_res *resp = &hdr->res;
+       u64 size = argp->offset + resp->count;
 
        if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
+               fattr->size = size;
+       if (nfs_size_to_loff_t(fattr->size) < i_size_read(hdr->inode)) {
+               fattr->valid &= ~NFS_ATTR_FATTR_SIZE;
                return;
-       if (argp->offset + resp->count != fattr->size)
-               return;
-       if (nfs_size_to_loff_t(fattr->size) < i_size_read(hdr->inode))
+       }
+       if (size != fattr->size)
                return;
        /* Set attribute barrier */
        nfs_fattr_set_barrier(fattr);
+       /* ...and update size */
+       fattr->valid |= NFS_ATTR_FATTR_SIZE;
 }
 
 void nfs_writeback_update_inode(struct nfs_pgio_header *hdr)
 {
-       struct nfs_fattr *fattr = hdr->res.fattr;
+       struct nfs_fattr *fattr = &hdr->fattr;
        struct inode *inode = hdr->inode;
 
-       if (fattr == NULL)
-               return;
        spin_lock(&inode->i_lock);
        nfs_writeback_check_extend(hdr, fattr);
        nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
index 6904213a436368e47628af85701a3beb68e0550b..ebf90e487c752b59270aa559588a8805468ad0f5 100644 (file)
@@ -212,6 +212,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
        BUG_ON(!ls->ls_file);
 
        if (nfsd4_layout_setlease(ls)) {
+               fput(ls->ls_file);
                put_nfs4_file(fp);
                kmem_cache_free(nfs4_layout_stateid_cache, ls);
                return NULL;
index 61dfb33f05593c1b19dff8a5346dee37a3539d79..95202719a1fd26bd27ea71a2fe85ec1c248e8d13 100644 (file)
@@ -4396,9 +4396,9 @@ laundromat_main(struct work_struct *laundry)
        queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
 }
 
-static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
+static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
 {
-       if (!fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle))
+       if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle))
                return nfserr_bad_stateid;
        return nfs_ok;
 }
@@ -4601,9 +4601,6 @@ nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags)
 {
        __be32 status;
 
-       status = nfs4_check_fh(fhp, ols);
-       if (status)
-               return status;
        status = nfsd4_check_openowner_confirmed(ols);
        if (status)
                return status;
@@ -4690,6 +4687,9 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
                status = nfserr_bad_stateid;
                break;
        }
+       if (status)
+               goto out;
+       status = nfs4_check_fh(fhp, s);
 
 done:
        if (!status && filpp)
@@ -4798,7 +4798,7 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
        status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
        if (status)
                return status;
-       return nfs4_check_fh(current_fh, stp);
+       return nfs4_check_fh(current_fh, &stp->st_stid);
 }
 
 /* 
index 54633858733a8da5ac978fe1d19a0a055488e01d..75e0563c09d1911d927501ee52b53a3bd988940e 100644 (file)
@@ -2143,6 +2143,7 @@ nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
                              FATTR4_WORD0_RDATTR_ERROR)
 #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
+#define WORD2_ABSENT_FS_ATTRS 0
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 static inline __be32
@@ -2171,7 +2172,7 @@ nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 { return 0; }
 #endif
 
-static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 *rdattr_err)
 {
        /* As per referral draft:  */
        if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
@@ -2184,6 +2185,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
        }
        *bmval0 &= WORD0_ABSENT_FS_ATTRS;
        *bmval1 &= WORD1_ABSENT_FS_ATTRS;
+       *bmval2 &= WORD2_ABSENT_FS_ATTRS;
        return 0;
 }
 
@@ -2246,8 +2248,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion));
 
        if (exp->ex_fslocs.migrated) {
-               BUG_ON(bmval[2]);
-               status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
+               status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err);
                if (status)
                        goto out;
        }
@@ -2286,8 +2287,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        }
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-       if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) ||
-                       bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
+       if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) ||
+            bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
                err = security_inode_getsecctx(d_inode(dentry),
                                                &context, &contextlen);
                contextsupport = (err == 0);
index 3e594ce410101bbab3e39b97e311f3aa79cf181c..39ddcaf0918f145fb3f2cb916d27aa1b866a220e 100644 (file)
@@ -152,15 +152,31 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark,
                BUG();
 
        list_del_init(&mark->g_list);
+
        spin_unlock(&mark->lock);
 
        if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED))
                iput(inode);
+       /* release lock temporarily */
+       mutex_unlock(&group->mark_mutex);
 
        spin_lock(&destroy_lock);
        list_add(&mark->g_list, &destroy_list);
        spin_unlock(&destroy_lock);
        wake_up(&destroy_waitq);
+       /*
+        * We don't necessarily have a ref on mark from caller so the above destroy
+        * may have actually freed it, unless this group provides a 'freeing_mark'
+        * function which must be holding a reference.
+        */
+
+       /*
+        * Some groups like to know that marks are being freed.  This is a
+        * callback to the group function to let it know that this mark
+        * is being freed.
+        */
+       if (group->ops->freeing_mark)
+               group->ops->freeing_mark(mark, group);
 
        /*
         * __fsnotify_update_child_dentry_flags(inode);
@@ -175,6 +191,8 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark,
         */
 
        atomic_dec(&group->num_marks);
+
+       mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
 }
 
 void fsnotify_destroy_mark(struct fsnotify_mark *mark,
@@ -187,10 +205,7 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark,
 
 /*
  * Destroy all marks in the given list. The marks must be already detached from
- * the original inode / vfsmount. Note that we can race with
- * fsnotify_clear_marks_by_group_flags(). However we hold a reference to each
- * mark so they won't get freed from under us and nobody else touches our
- * free_list list_head.
+ * the original inode / vfsmount.
  */
 void fsnotify_destroy_marks(struct list_head *to_free)
 {
@@ -391,22 +406,42 @@ struct fsnotify_mark *fsnotify_find_mark(struct hlist_head *head,
 }
 
 /*
- * Clear any marks in a group in which mark->flags & flags is true.
+ * clear any marks in a group in which mark->flags & flags is true
  */
 void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
                                         unsigned int flags)
 {
        struct fsnotify_mark *lmark, *mark;
+       LIST_HEAD(to_free);
 
+       /*
+        * We have to be really careful here. Anytime we drop mark_mutex, e.g.
+        * fsnotify_clear_marks_by_inode() can come and free marks. Even in our
+        * to_free list so we have to use mark_mutex even when accessing that
+        * list. And freeing mark requires us to drop mark_mutex. So we can
+        * reliably free only the first mark in the list. That's why we first
+        * move marks to free to to_free list in one go and then free marks in
+        * to_free list one by one.
+        */
        mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
        list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
-               if (mark->flags & flags) {
-                       fsnotify_get_mark(mark);
-                       fsnotify_destroy_mark_locked(mark, group);
-                       fsnotify_put_mark(mark);
-               }
+               if (mark->flags & flags)
+                       list_move(&mark->g_list, &to_free);
        }
        mutex_unlock(&group->mark_mutex);
+
+       while (1) {
+               mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
+               if (list_empty(&to_free)) {
+                       mutex_unlock(&group->mark_mutex);
+                       break;
+               }
+               mark = list_first_entry(&to_free, struct fsnotify_mark, g_list);
+               fsnotify_get_mark(mark);
+               fsnotify_destroy_mark_locked(mark, group);
+               mutex_unlock(&group->mark_mutex);
+               fsnotify_put_mark(mark);
+       }
 }
 
 /*
@@ -445,7 +480,6 @@ static int fsnotify_mark_destroy(void *ignored)
 {
        struct fsnotify_mark *mark, *next;
        struct list_head private_destroy_list;
-       struct fsnotify_group *group;
 
        for (;;) {
                spin_lock(&destroy_lock);
@@ -457,14 +491,6 @@ static int fsnotify_mark_destroy(void *ignored)
 
                list_for_each_entry_safe(mark, next, &private_destroy_list, g_list) {
                        list_del_init(&mark->g_list);
-                       group = mark->group;
-                       /*
-                        * Some groups like to know that marks are being freed.
-                        * This is a callback to the group function to let it
-                        * know that this mark is being freed.
-                        */
-                       if (group && group->ops->freeing_mark)
-                               group->ops->freeing_mark(mark, group);
                        fsnotify_put_mark(mark);
                }
 
index 1a35c6139656344516aacd59c7120f6fb877f2a2..0f5fd9db8194ef5d135f1896f6e2645a5f059cd8 100644 (file)
@@ -685,7 +685,7 @@ static int ocfs2_direct_IO_zero_extend(struct ocfs2_super *osb,
 
        if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) {
                u64 s = i_size_read(inode);
-               sector_t sector = (p_cpos << (osb->s_clustersize_bits - 9)) +
+               sector_t sector = ((u64)p_cpos << (osb->s_clustersize_bits - 9)) +
                        (do_div(s, osb->s_clustersize) >> 9);
 
                ret = blkdev_issue_zeroout(osb->sb->s_bdev, sector,
@@ -910,7 +910,7 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb,
                BUG_ON(!p_cpos || (ext_flags & OCFS2_EXT_UNWRITTEN));
 
                ret = blkdev_issue_zeroout(osb->sb->s_bdev,
-                               p_cpos << (osb->s_clustersize_bits - 9),
+                               (u64)p_cpos << (osb->s_clustersize_bits - 9),
                                zero_len_head >> 9, GFP_NOFS, false);
                if (ret < 0)
                        mlog_errno(ret);
index 8b23aa2f52ddafe31be83b730d7219693222a1c5..23157e40dd740204bc10f9eaeb55ec08f2f0dfb4 100644 (file)
@@ -4025,9 +4025,13 @@ static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb)
        osb->dc_work_sequence = osb->dc_wake_sequence;
 
        processed = osb->blocked_lock_count;
-       while (processed) {
-               BUG_ON(list_empty(&osb->blocked_lock_list));
-
+       /*
+        * blocked lock processing in this loop might call iput which can
+        * remove items off osb->blocked_lock_list. Downconvert up to
+        * 'processed' number of locks, but stop short if we had some
+        * removed in ocfs2_mark_lockres_freeing when downconverting.
+        */
+       while (processed && !list_empty(&osb->blocked_lock_list)) {
                lockres = list_entry(osb->blocked_lock_list.next,
                                     struct ocfs2_lock_res, l_blocked_list);
                list_del_init(&lockres->l_blocked_list);
index 7114ce6e6b9ef038f415550b925ac50a95be978c..0fcdbe7ca6480e7950092cfd0dc7d0ce431ef548 100644 (file)
@@ -20,8 +20,6 @@
 #define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED)
 #define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED)
 #define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED)
-#define IS_MNT_LOCKED_AND_LAZY(m) \
-       (((m)->mnt.mnt_flags & (MNT_LOCKED|MNT_SYNC_UMOUNT)) == MNT_LOCKED)
 
 #define CL_EXPIRE              0x01
 #define CL_SLAVE               0x02
index 7e412ad748363489baad12cbb644b8074d78cfeb..270221fcef42cc42fcfdbc098b587b571be65a12 100644 (file)
@@ -121,8 +121,9 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitly for the right codes here.
                 */
-               if (kinfo->si_code == BUS_MCEERR_AR ||
-                   kinfo->si_code == BUS_MCEERR_AO)
+               if (kinfo->si_signo == SIGBUS &&
+                   (kinfo->si_code == BUS_MCEERR_AR ||
+                    kinfo->si_code == BUS_MCEERR_AO))
                        err |= __put_user((short) kinfo->si_addr_lsb,
                                          &uinfo->ssi_addr_lsb);
 #endif
index 6afac3d561ac81f6f5861f86a0dc4eb2a7d1fca2..8d0b3ade0ff0ef8a65f8714330a3bfd49201c0d8 100644 (file)
@@ -1652,17 +1652,9 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                       iinfo->i_ext.i_data, inode->i_sb->s_blocksize -
                                        sizeof(struct unallocSpaceEntry));
                use->descTag.tagIdent = cpu_to_le16(TAG_IDENT_USE);
-               use->descTag.tagLocation =
-                               cpu_to_le32(iinfo->i_location.logicalBlockNum);
-               crclen = sizeof(struct unallocSpaceEntry) +
-                               iinfo->i_lenAlloc - sizeof(struct tag);
-               use->descTag.descCRCLength = cpu_to_le16(crclen);
-               use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use +
-                                                          sizeof(struct tag),
-                                                          crclen));
-               use->descTag.tagChecksum = udf_tag_checksum(&use->descTag);
+               crclen = sizeof(struct unallocSpaceEntry);
 
-               goto out;
+               goto finish;
        }
 
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET))
@@ -1782,6 +1774,8 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE);
                crclen = sizeof(struct extendedFileEntry);
        }
+
+finish:
        if (iinfo->i_strat4096) {
                fe->icbTag.strategyType = cpu_to_le16(4096);
                fe->icbTag.strategyParameter = cpu_to_le16(1);
@@ -1791,7 +1785,9 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                fe->icbTag.numEntries = cpu_to_le16(1);
        }
 
-       if (S_ISDIR(inode->i_mode))
+       if (iinfo->i_use)
+               fe->icbTag.fileType = ICBTAG_FILE_TYPE_USE;
+       else if (S_ISDIR(inode->i_mode))
                fe->icbTag.fileType = ICBTAG_FILE_TYPE_DIRECTORY;
        else if (S_ISREG(inode->i_mode))
                fe->icbTag.fileType = ICBTAG_FILE_TYPE_REGULAR;
@@ -1828,7 +1824,6 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                                                  crclen));
        fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag);
 
-out:
        set_buffer_uptodate(bh);
        unlock_buffer(bh);
 
index 20de88d1bf86205d126d5e27b43298af9b836a79..dd714037c322d0009d8df40e73bf5adf3aa892d4 100644 (file)
@@ -159,11 +159,10 @@ xfs_attr3_rmt_write_verify(
        struct xfs_buf  *bp)
 {
        struct xfs_mount *mp = bp->b_target->bt_mount;
-       struct xfs_buf_log_item *bip = bp->b_fspriv;
+       int             blksize = mp->m_attr_geo->blksize;
        char            *ptr;
        int             len;
        xfs_daddr_t     bno;
-       int             blksize = mp->m_attr_geo->blksize;
 
        /* no verification of non-crc buffers */
        if (!xfs_sb_version_hascrc(&mp->m_sb))
@@ -175,16 +174,22 @@ xfs_attr3_rmt_write_verify(
        ASSERT(len >= blksize);
 
        while (len > 0) {
+               struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
+
                if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
                        xfs_buf_ioerror(bp, -EFSCORRUPTED);
                        xfs_verifier_error(bp);
                        return;
                }
-               if (bip) {
-                       struct xfs_attr3_rmt_hdr *rmt;
 
-                       rmt = (struct xfs_attr3_rmt_hdr *)ptr;
-                       rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn);
+               /*
+                * Ensure we aren't writing bogus LSNs to disk. See
+                * xfs_attr3_rmt_hdr_set() for the explanation.
+                */
+               if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
+                       xfs_buf_ioerror(bp, -EFSCORRUPTED);
+                       xfs_verifier_error(bp);
+                       return;
                }
                xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
 
@@ -221,6 +226,18 @@ xfs_attr3_rmt_hdr_set(
        rmt->rm_owner = cpu_to_be64(ino);
        rmt->rm_blkno = cpu_to_be64(bno);
 
+       /*
+        * Remote attribute blocks are written synchronously, so we don't
+        * have an LSN that we can stamp in them that makes any sense to log
+        * recovery. To ensure that log recovery handles overwrites of these
+        * blocks sanely (i.e. once they've been freed and reallocated as some
+        * other type of metadata) we need to ensure that the LSN has a value
+        * that tells log recovery to ignore the LSN and overwrite the buffer
+        * with whatever is in it's log. To do this, we use the magic
+        * NULLCOMMITLSN to indicate that the LSN is invalid.
+        */
+       rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
+
        return sizeof(struct xfs_attr3_rmt_hdr);
 }
 
@@ -434,14 +451,21 @@ xfs_attr_rmtval_set(
 
                /*
                 * Allocate a single extent, up to the size of the value.
+                *
+                * Note that we have to consider this a data allocation as we
+                * write the remote attribute without logging the contents.
+                * Hence we must ensure that we aren't using blocks that are on
+                * the busy list so that we don't overwrite blocks which have
+                * recently been freed but their transactions are not yet
+                * committed to disk. If we overwrite the contents of a busy
+                * extent and then crash then the block may not contain the
+                * correct metadata after log recovery occurs.
                 */
                xfs_bmap_init(args->flist, args->firstblock);
                nmap = 1;
                error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
-                                 blkcnt,
-                                 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                 args->firstblock, args->total, &map, &nmap,
-                                 args->flist);
+                                 blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock,
+                                 args->total, &map, &nmap, args->flist);
                if (!error) {
                        error = xfs_bmap_finish(&args->trans, args->flist,
                                                &committed);
index f0e8249722d40a0dcaf9f31bc25effaba142b0a9..db4acc1c3e73479cdf32322944a7fa1bcf34b96f 100644 (file)
@@ -1514,18 +1514,27 @@ xfs_filemap_fault(
        struct vm_area_struct   *vma,
        struct vm_fault         *vmf)
 {
-       struct xfs_inode        *ip = XFS_I(file_inode(vma->vm_file));
+       struct inode            *inode = file_inode(vma->vm_file);
        int                     ret;
 
-       trace_xfs_filemap_fault(ip);
+       trace_xfs_filemap_fault(XFS_I(inode));
 
        /* DAX can shortcut the normal fault path on write faults! */
-       if ((vmf->flags & FAULT_FLAG_WRITE) && IS_DAX(VFS_I(ip)))
+       if ((vmf->flags & FAULT_FLAG_WRITE) && IS_DAX(inode))
                return xfs_filemap_page_mkwrite(vma, vmf);
 
-       xfs_ilock(ip, XFS_MMAPLOCK_SHARED);
-       ret = filemap_fault(vma, vmf);
-       xfs_iunlock(ip, XFS_MMAPLOCK_SHARED);
+       xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
+       if (IS_DAX(inode)) {
+               /*
+                * we do not want to trigger unwritten extent conversion on read
+                * faults - that is unnecessary overhead and would also require
+                * changes to xfs_get_blocks_direct() to map unwritten extent
+                * ioend for conversion on read-only mappings.
+                */
+               ret = __dax_fault(vma, vmf, xfs_get_blocks_direct, NULL);
+       } else
+               ret = filemap_fault(vma, vmf);
+       xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
 
        return ret;
 }
index 01dd228ca05e315b88feb7afbfaf3e81d728878b..480ebba8464f38dbb0608b579185ad93a0600913 100644 (file)
@@ -1886,9 +1886,14 @@ xlog_recover_get_buf_lsn(
                uuid = &((struct xfs_dir3_blk_hdr *)blk)->uuid;
                break;
        case XFS_ATTR3_RMT_MAGIC:
-               lsn = be64_to_cpu(((struct xfs_attr3_rmt_hdr *)blk)->rm_lsn);
-               uuid = &((struct xfs_attr3_rmt_hdr *)blk)->rm_uuid;
-               break;
+               /*
+                * Remote attr blocks are written synchronously, rather than
+                * being logged. That means they do not contain a valid LSN
+                * (i.e. transactionally ordered) in them, and hence any time we
+                * see a buffer to replay over the top of a remote attribute
+                * block we should simply do so.
+                */
+               goto recover_immediately;
        case XFS_SB_MAGIC:
                lsn = be64_to_cpu(((struct xfs_dsb *)blk)->sb_lsn);
                uuid = &((struct xfs_dsb *)blk)->sb_uuid;
index 3b0c50f7412a1d1c522f76712869f6c0a5e2187b..8b5ce7c5d9bbfc33250ea8d15621cfd1d97be3f4 100644 (file)
@@ -681,7 +681,7 @@ struct drm_minor {
 
 struct drm_pending_vblank_event {
        struct drm_pending_event base;
-       int pipe;
+       unsigned int pipe;
        struct drm_event_vblank event;
 };
 
@@ -691,7 +691,7 @@ struct drm_vblank_crtc {
        struct timer_list disable_timer;                /* delayed disable timer */
 
        /* vblank counter, protected by dev->vblank_time_lock for writes */
-       unsigned long count;
+       u32 count;
        /* vblank timestamps, protected by dev->vblank_time_lock for writes */
        struct timeval time[DRM_VBLANKTIME_RBSIZE];
 
@@ -700,7 +700,7 @@ struct drm_vblank_crtc {
                                        /* for wraparound handling */
        u32 last_wait;                  /* Last vblank seqno waited per CRTC */
        unsigned int inmodeset;         /* Display driver is setting mode */
-       int crtc;                       /* crtc index */
+       unsigned int pipe;              /* crtc index */
        bool enabled;                   /* so we don't call enable more than
                                           once per disable */
 };
@@ -921,34 +921,34 @@ void drm_clflush_virt_range(void *addr, unsigned long length);
 extern int drm_irq_install(struct drm_device *dev, int irq);
 extern int drm_irq_uninstall(struct drm_device *dev);
 
-extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
+extern int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs);
 extern int drm_wait_vblank(struct drm_device *dev, void *data,
                           struct drm_file *filp);
-extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
+extern u32 drm_vblank_count(struct drm_device *dev, int pipe);
 extern u32 drm_crtc_vblank_count(struct drm_crtc *crtc);
-extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
+extern u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe,
                                     struct timeval *vblanktime);
-extern void drm_send_vblank_event(struct drm_device *dev, int crtc,
-                                    struct drm_pending_vblank_event *e);
+extern void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe,
+                                 struct drm_pending_vblank_event *e);
 extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
                                       struct drm_pending_vblank_event *e);
-extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
+extern bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe);
 extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
-extern int drm_vblank_get(struct drm_device *dev, int crtc);
-extern void drm_vblank_put(struct drm_device *dev, int crtc);
+extern int drm_vblank_get(struct drm_device *dev, unsigned int pipe);
+extern void drm_vblank_put(struct drm_device *dev, unsigned int pipe);
 extern int drm_crtc_vblank_get(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_put(struct drm_crtc *crtc);
-extern void drm_wait_one_vblank(struct drm_device *dev, int crtc);
+extern void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe);
 extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
-extern void drm_vblank_off(struct drm_device *dev, int crtc);
-extern void drm_vblank_on(struct drm_device *dev, int crtc);
+extern void drm_vblank_off(struct drm_device *dev, unsigned int pipe);
+extern void drm_vblank_on(struct drm_device *dev, unsigned int pipe);
 extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
 extern void drm_vblank_cleanup(struct drm_device *dev);
 
 extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
-                                                int crtc, int *max_error,
+                                                unsigned int pipe, int *max_error,
                                                 struct timeval *vblank_time,
                                                 unsigned flags,
                                                 const struct drm_crtc *refcrtc,
@@ -969,8 +969,8 @@ static inline wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc
 }
 
 /* Modesetting support */
-extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
-extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc);
+extern void drm_vblank_pre_modeset(struct drm_device *dev, unsigned int pipe);
+extern void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe);
 
                                /* Stub support (drm_stub.h) */
 extern struct drm_master *drm_master_get(struct drm_master *master);
index 8a3a913320ebb10647fea413430a3871f1f34eb1..e67aeac2aee05c077eec5a47abc9d73eef6831d6 100644 (file)
@@ -166,7 +166,8 @@ int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
 static inline bool
 drm_atomic_crtc_needs_modeset(struct drm_crtc_state *state)
 {
-       return state->mode_changed || state->active_changed;
+       return state->mode_changed || state->active_changed ||
+              state->connectors_changed;
 }
 
 
index cc1fee8a12d0a5e71babb3626644604618b987ba..11266d147a29409b12718a1b575520579d588fde 100644 (file)
@@ -87,8 +87,8 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
                                struct drm_framebuffer *fb,
                                struct drm_pending_vblank_event *event,
                                uint32_t flags);
-void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
-                                     int mode);
+int drm_atomic_helper_connector_dpms(struct drm_connector *connector,
+                                    int mode);
 
 /* default implementations for state handling */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
index 3071319ea19406190a566b3c1daf84a42d2003f9..6e5afc30b59672b8a2f6c6b5e0256bd8be04593d 100644 (file)
@@ -255,12 +255,13 @@ struct drm_atomic_state;
  * @crtc: backpointer to the CRTC
  * @enable: whether the CRTC should be enabled, gates all other state
  * @active: whether the CRTC is actively displaying (used for DPMS)
- * @mode_changed: for use by helpers and drivers when computing state updates
- * @active_changed: for use by helpers and drivers when computing state updates
+ * @planes_changed: planes on this crtc are updated
+ * @mode_changed: crtc_state->mode or crtc_state->enable has been changed
+ * @active_changed: crtc_state->active has been toggled.
+ * @connectors_changed: connectors to this crtc have been updated
  * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
  * @last_vblank_count: for helpers and drivers to capture the vblank of the
  *     update to ensure framebuffer cleanup isn't done too early
- * @planes_changed: for use by helpers and drivers when computing state updates
  * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
  * @mode: current mode timings
  * @event: optional pointer to a DRM event to signal upon completion of the
@@ -283,6 +284,7 @@ struct drm_crtc_state {
        bool planes_changed : 1;
        bool mode_changed : 1;
        bool active_changed : 1;
+       bool connectors_changed : 1;
 
        /* attached planes bitmask:
         * WARNING: transitional helpers do not maintain plane_mask so
@@ -525,7 +527,7 @@ struct drm_connector_state {
  * etc.
  */
 struct drm_connector_funcs {
-       void (*dpms)(struct drm_connector *connector, int mode);
+       int (*dpms)(struct drm_connector *connector, int mode);
        void (*save)(struct drm_connector *connector);
        void (*restore)(struct drm_connector *connector);
        void (*reset)(struct drm_connector *connector);
@@ -863,7 +865,7 @@ struct drm_plane {
 
        uint32_t possible_crtcs;
        uint32_t *format_types;
-       uint32_t format_count;
+       unsigned int format_count;
        bool format_default;
 
        struct drm_crtc *crtc;
@@ -1268,13 +1270,13 @@ extern int drm_universal_plane_init(struct drm_device *dev,
                                    unsigned long possible_crtcs,
                                    const struct drm_plane_funcs *funcs,
                                    const uint32_t *formats,
-                                   uint32_t format_count,
+                                   unsigned int format_count,
                                    enum drm_plane_type type);
 extern int drm_plane_init(struct drm_device *dev,
                          struct drm_plane *plane,
                          unsigned long possible_crtcs,
                          const struct drm_plane_funcs *funcs,
-                         const uint32_t *formats, uint32_t format_count,
+                         const uint32_t *formats, unsigned int format_count,
                          bool is_primary);
 extern void drm_plane_cleanup(struct drm_plane *plane);
 extern unsigned int drm_plane_index(struct drm_plane *plane);
index c8fc187061de5fbd9fc8545f602a62baaa45b8cc..2a747a91fdede982354438e1c48fc1a332d06885 100644 (file)
@@ -108,8 +108,10 @@ struct drm_crtc_helper_funcs {
        /* atomic helpers */
        int (*atomic_check)(struct drm_crtc *crtc,
                            struct drm_crtc_state *state);
-       void (*atomic_begin)(struct drm_crtc *crtc);
-       void (*atomic_flush)(struct drm_crtc *crtc);
+       void (*atomic_begin)(struct drm_crtc *crtc,
+                            struct drm_crtc_state *old_crtc_state);
+       void (*atomic_flush)(struct drm_crtc *crtc,
+                            struct drm_crtc_state *old_crtc_state);
 };
 
 /**
@@ -168,6 +170,7 @@ struct drm_encoder_helper_funcs {
  * @get_modes: get mode list for this connector
  * @mode_valid: is this mode valid on the given connector? (optional)
  * @best_encoder: return the preferred encoder for this connector
+ * @atomic_best_encoder: atomic version of @best_encoder
  *
  * The helper operations are called by the mid-layer CRTC helper.
  */
@@ -176,6 +179,8 @@ struct drm_connector_helper_funcs {
        enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
                                           struct drm_display_mode *mode);
        struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
+       struct drm_encoder *(*atomic_best_encoder)(struct drm_connector *connector,
+                                                  struct drm_connector_state *connector_state);
 };
 
 extern void drm_helper_disable_unused_functions(struct drm_device *dev);
@@ -187,7 +192,7 @@ extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc);
 extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder);
 
-extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode);
+extern int drm_helper_connector_dpms(struct drm_connector *connector, int mode);
 
 extern void drm_helper_move_panel_connectors_to_head(struct drm_device *);
 
index 2e86f642fc3390f5909a87d2edeb6bdb97a626f6..94898f6ea02af17d84dbbe46f0c8e8818b5b9124 100644 (file)
 
 #define DP_TEST_SINK_MISC                  0x246
 # define DP_TEST_CRC_SUPPORTED             (1 << 5)
-# define DP_TEST_COUNT_MASK                0x7
+# define DP_TEST_COUNT_MASK                0xf
 
 #define DP_TEST_RESPONSE                   0x260
 # define DP_TEST_ACK                       (1 << 0)
index 0dfd94def593526eaa7d5e414a85634f37509385..dbab4622b58f7195b089d8fcadd27f31aec36e02 100644 (file)
@@ -122,6 +122,7 @@ struct drm_fb_helper {
        bool delayed_hotplug;
 };
 
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
                           const struct drm_fb_helper_funcs *funcs);
 int drm_fb_helper_init(struct drm_device *dev,
@@ -136,11 +137,38 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
                            struct fb_info *info);
 
 bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper);
+
+struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper);
+void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper);
+void drm_fb_helper_release_fbi(struct drm_fb_helper *fb_helper);
 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
                            uint32_t fb_width, uint32_t fb_height);
 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
                            uint32_t depth);
 
+void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper);
+
+ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
+                              size_t count, loff_t *ppos);
+ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
+                               size_t count, loff_t *ppos);
+
+void drm_fb_helper_sys_fillrect(struct fb_info *info,
+                               const struct fb_fillrect *rect);
+void drm_fb_helper_sys_copyarea(struct fb_info *info,
+                               const struct fb_copyarea *area);
+void drm_fb_helper_sys_imageblit(struct fb_info *info,
+                                const struct fb_image *image);
+
+void drm_fb_helper_cfb_fillrect(struct fb_info *info,
+                               const struct fb_fillrect *rect);
+void drm_fb_helper_cfb_copyarea(struct fb_info *info,
+                               const struct fb_copyarea *area);
+void drm_fb_helper_cfb_imageblit(struct fb_info *info,
+                                const struct fb_image *image);
+
+void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state);
+
 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
 
 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
@@ -158,4 +186,188 @@ drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
 int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector);
 int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
                                       struct drm_connector *connector);
+#else
+static inline void drm_fb_helper_prepare(struct drm_device *dev,
+                                       struct drm_fb_helper *helper,
+                                       const struct drm_fb_helper_funcs *funcs)
+{
+}
+
+static inline int drm_fb_helper_init(struct drm_device *dev,
+                      struct drm_fb_helper *helper, int crtc_count,
+                      int max_conn)
+{
+       return 0;
+}
+
+static inline void drm_fb_helper_fini(struct drm_fb_helper *helper)
+{
+}
+
+static inline int drm_fb_helper_blank(int blank, struct fb_info *info)
+{
+       return 0;
+}
+
+static inline int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
+                                           struct fb_info *info)
+{
+       return 0;
+}
+
+static inline int drm_fb_helper_set_par(struct fb_info *info)
+{
+       return 0;
+}
+
+static inline int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
+                                         struct fb_info *info)
+{
+       return 0;
+}
+
+static inline bool
+drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
+{
+       return true;
+}
+
+static inline struct fb_info *
+drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
+{
+       return NULL;
+}
+
+static inline void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
+{
+}
+static inline void drm_fb_helper_release_fbi(struct drm_fb_helper *fb_helper)
+{
+}
+
+static inline void drm_fb_helper_fill_var(struct fb_info *info,
+                                         struct drm_fb_helper *fb_helper,
+                                         uint32_t fb_width, uint32_t fb_height)
+{
+}
+
+static inline void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
+                                         uint32_t depth)
+{
+}
+
+static inline int drm_fb_helper_setcmap(struct fb_cmap *cmap,
+                                       struct fb_info *info)
+{
+       return 0;
+}
+
+static inline void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
+{
+}
+
+static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info,
+                                            char __user *buf, size_t count,
+                                            loff_t *ppos)
+{
+       return -ENODEV;
+}
+
+static inline ssize_t drm_fb_helper_sys_write(struct fb_info *info,
+                                             const char __user *buf,
+                                             size_t count, loff_t *ppos)
+{
+       return -ENODEV;
+}
+
+static inline void drm_fb_helper_sys_fillrect(struct fb_info *info,
+                                             const struct fb_fillrect *rect)
+{
+}
+
+static inline void drm_fb_helper_sys_copyarea(struct fb_info *info,
+                                             const struct fb_copyarea *area)
+{
+}
+
+static inline void drm_fb_helper_sys_imageblit(struct fb_info *info,
+                                              const struct fb_image *image)
+{
+}
+
+static inline void drm_fb_helper_cfb_fillrect(struct fb_info *info,
+                                             const struct fb_fillrect *rect)
+{
+}
+
+static inline void drm_fb_helper_cfb_copyarea(struct fb_info *info,
+                                             const struct fb_copyarea *area)
+{
+}
+
+static inline void drm_fb_helper_cfb_imageblit(struct fb_info *info,
+                                              const struct fb_image *image)
+{
+}
+
+static inline void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper,
+                                            int state)
+{
+}
+
+static inline int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
+{
+       return 0;
+}
+
+static inline int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper,
+                                              int bpp_sel)
+{
+       return 0;
+}
+
+static inline int
+drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
+{
+       return 0;
+}
+
+static inline int drm_fb_helper_debug_enter(struct fb_info *info)
+{
+       return 0;
+}
+
+static inline int drm_fb_helper_debug_leave(struct fb_info *info)
+{
+       return 0;
+}
+
+static inline struct drm_display_mode *
+drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector,
+                      int width, int height)
+{
+       return NULL;
+}
+
+static inline struct drm_display_mode *
+drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
+                     int width, int height)
+{
+       return NULL;
+}
+
+static inline int
+drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
+                               struct drm_connector *connector)
+{
+       return 0;
+}
+
+static inline int
+drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
+                                  struct drm_connector *connector)
+{
+       return 0;
+}
+#endif
 #endif
index 70595ff565baa45190faaae5c42630fe04a1beff..5dd18bfdf6017daed071135d5cbbc20111f16b34 100644 (file)
@@ -130,7 +130,6 @@ struct drm_crtc;
 struct drm_plane;
 
 void drm_modeset_lock_all(struct drm_device *dev);
-int __drm_modeset_lock_all(struct drm_device *dev, bool trylock);
 void drm_modeset_unlock_all(struct drm_device *dev);
 void drm_modeset_lock_crtc(struct drm_crtc *crtc,
                           struct drm_plane *plane);
index 45c39a37f9249562761dc9615ffecf12ec194846..8bc073d297db2a233cf389d6c0656dec78c0445a 100644 (file)
        {0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6617, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6620, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
index 96e16283afb96ca3227a96733e6e6ff57acaac2a..dda401bf910e1eace1dbecbb7db92ca342ace306 100644 (file)
@@ -43,9 +43,8 @@
  * planes.
  */
 
-extern int drm_crtc_init(struct drm_device *dev,
-                        struct drm_crtc *crtc,
-                        const struct drm_crtc_funcs *funcs);
+int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+                 const struct drm_crtc_funcs *funcs);
 
 /**
  * drm_plane_helper_funcs - helper operations for CRTCs
@@ -79,26 +78,26 @@ static inline void drm_plane_helper_add(struct drm_plane *plane,
        plane->helper_private = funcs;
 }
 
-extern int drm_plane_helper_check_update(struct drm_plane *plane,
-                                        struct drm_crtc *crtc,
-                                        struct drm_framebuffer *fb,
-                                        struct drm_rect *src,
-                                        struct drm_rect *dest,
-                                        const struct drm_rect *clip,
-                                        int min_scale,
-                                        int max_scale,
-                                        bool can_position,
-                                        bool can_update_disabled,
-                                        bool *visible);
-extern int drm_primary_helper_update(struct drm_plane *plane,
-                                    struct drm_crtc *crtc,
-                                    struct drm_framebuffer *fb,
-                                    int crtc_x, int crtc_y,
-                                    unsigned int crtc_w, unsigned int crtc_h,
-                                    uint32_t src_x, uint32_t src_y,
-                                    uint32_t src_w, uint32_t src_h);
-extern int drm_primary_helper_disable(struct drm_plane *plane);
-extern void drm_primary_helper_destroy(struct drm_plane *plane);
+int drm_plane_helper_check_update(struct drm_plane *plane,
+                                 struct drm_crtc *crtc,
+                                 struct drm_framebuffer *fb,
+                                 struct drm_rect *src,
+                                 struct drm_rect *dest,
+                                 const struct drm_rect *clip,
+                                 int min_scale,
+                                 int max_scale,
+                                 bool can_position,
+                                 bool can_update_disabled,
+                                 bool *visible);
+int drm_primary_helper_update(struct drm_plane *plane,
+                             struct drm_crtc *crtc,
+                             struct drm_framebuffer *fb,
+                             int crtc_x, int crtc_y,
+                             unsigned int crtc_w, unsigned int crtc_h,
+                             uint32_t src_x, uint32_t src_y,
+                             uint32_t src_w, uint32_t src_h);
+int drm_primary_helper_disable(struct drm_plane *plane);
+void drm_primary_helper_destroy(struct drm_plane *plane);
 extern const struct drm_plane_funcs drm_primary_helper_funcs;
 
 int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
index fed36418dd1c2fe8c1c084278080f2ff23169725..6c78956aa47092440edb3a73e7b9389ac3a57558 100644 (file)
@@ -45,6 +45,7 @@ enum {
        ATA_SECT_SIZE           = 512,
        ATA_MAX_SECTORS_128     = 128,
        ATA_MAX_SECTORS         = 256,
+       ATA_MAX_SECTORS_1024    = 1024,
        ATA_MAX_SECTORS_LBA48   = 65535,/* TODO: 65536? */
        ATA_MAX_SECTORS_TAPE    = 65535,
 
index 76abba4b238ece14f8a2bd9bcce5ab53306c61fd..dcacb1a72e26d0755703135016105ae511a2b042 100644 (file)
@@ -340,7 +340,27 @@ struct cper_ia_proc_ctx {
        __u64   mm_reg_addr;
 };
 
-/* Memory Error Section */
+/* Old Memory Error Section UEFI 2.1, 2.2 */
+struct cper_sec_mem_err_old {
+       __u64   validation_bits;
+       __u64   error_status;
+       __u64   physical_addr;
+       __u64   physical_addr_mask;
+       __u16   node;
+       __u16   card;
+       __u16   module;
+       __u16   bank;
+       __u16   device;
+       __u16   row;
+       __u16   column;
+       __u16   bit_pos;
+       __u64   requestor_id;
+       __u64   responder_id;
+       __u64   target_id;
+       __u8    error_type;
+};
+
+/* Memory Error Section UEFI >= 2.3 */
 struct cper_sec_mem_err {
        __u64   validation_bits;
        __u64   error_status;
index 29ad97c34fd5cf4bcdeec373d2ad5691bb2ec6c3..bde1e567b3a93ad5feb7a0d2aa980a07e28270d5 100644 (file)
@@ -62,6 +62,7 @@ struct cpufreq_policy {
        /* CPUs sharing clock, require sw coordination */
        cpumask_var_t           cpus;   /* Online CPUs only */
        cpumask_var_t           related_cpus; /* Online + Offline CPUs */
+       cpumask_var_t           real_cpus; /* Related and present */
 
        unsigned int            shared_type; /* ACPI: ANY or ALL affected CPUs
                                                should set cpufreq */
index cc008c338f5a9bcb66076da96e929d6104697373..84b783f277f761a0ef7b940bd1fbab37db60567e 100644 (file)
@@ -55,7 +55,8 @@ struct vm_fault;
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
-extern void __init files_init(unsigned long);
+extern void __init files_init(void);
+extern void __init files_maxfiles_init(void);
 
 extern struct files_stat_struct files_stat;
 extern unsigned long get_max_files(void);
@@ -2245,7 +2246,7 @@ extern int ioctl_preallocate(struct file *filp, void __user *argp);
 
 /* fs/dcache.c */
 extern void __init vfs_caches_init_early(void);
-extern void __init vfs_caches_init(unsigned long);
+extern void __init vfs_caches_init(void);
 
 extern struct kmem_cache *names_cachep;
 
index 1da602982cf93a6a262bef85967945ffea9c586a..6cd8c0ee4b6f89a9ab93b67515cb6e214e108071 100644 (file)
@@ -116,6 +116,7 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops);
  *            SAVE_REGS. If another ops with this flag set is already registered
  *            for any of the functions that this ops will be registered for, then
  *            this ops will fail to register or set_filter_ip.
+ * PID     - Is affected by set_ftrace_pid (allows filtering on those pids)
  */
 enum {
        FTRACE_OPS_FL_ENABLED                   = 1 << 0,
@@ -132,6 +133,7 @@ enum {
        FTRACE_OPS_FL_MODIFYING                 = 1 << 11,
        FTRACE_OPS_FL_ALLOC_TRAMP               = 1 << 12,
        FTRACE_OPS_FL_IPMODIFY                  = 1 << 13,
+       FTRACE_OPS_FL_PID                       = 1 << 14,
 };
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -159,6 +161,7 @@ struct ftrace_ops {
        struct ftrace_ops               *next;
        unsigned long                   flags;
        void                            *private;
+       ftrace_func_t                   saved_func;
        int __percpu                    *disabled;
 #ifdef CONFIG_DYNAMIC_FTRACE
        int                             nr_trampolines;
index 36ce37bcc963c270548989d658caa4f3ce832045..c9cfbcdb8d140e2f136b724501a064a25a766fb3 100644 (file)
@@ -431,6 +431,8 @@ enum {
        ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21),  /* some WDs have broken LPM */
        ATA_HORKAGE_ZERO_AFTER_TRIM = (1 << 22),/* guarantees zero after trim */
        ATA_HORKAGE_NO_NCQ_LOG  = (1 << 23),    /* don't use NCQ for log read */
+       ATA_HORKAGE_NOTRIM      = (1 << 24),    /* don't use TRIM */
+       ATA_HORKAGE_MAX_SEC_1024 = (1 << 25),   /* Limit max sects to 1024 */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
index f25e2bdd188c94643efc0f3a94c7c67de81897aa..272f42952f3424aa43953b7e3a50b925a93bd465 100644 (file)
@@ -177,11 +177,6 @@ typedef enum {
 #define NAND_OWN_BUFFERS       0x00020000
 /* Chip may not exist, so silence any errors in scan */
 #define NAND_SCAN_SILENT_NODEV 0x00040000
-/*
- * This option could be defined by controller drivers to protect against
- * kmap'ed, vmalloc'ed highmem buffers being passed from upper layers
- */
-#define NAND_USE_BOUNCE_BUFFER 0x00080000
 /*
  * Autodetect nand buswidth with readid/onfi.
  * This suppose the driver will configure the hardware in 8 bits mode
@@ -189,6 +184,11 @@ typedef enum {
  * before calling nand_scan_tail.
  */
 #define NAND_BUSWIDTH_AUTO      0x00080000
+/*
+ * This option could be defined by controller drivers to protect against
+ * kmap'ed, vmalloc'ed highmem buffers being passed from upper layers
+ */
+#define NAND_USE_BOUNCE_BUFFER 0x00100000
 
 /* Options set by nand scan */
 /* Nand scan has allocated controller struct */
index f91b5ade30c98fe8b03d06bc40deb0c434edb633..874b77228fb96285fb2024f07fa99d1ed7dd6dda 100644 (file)
@@ -292,9 +292,12 @@ static inline void nfs_mark_for_revalidate(struct inode *inode)
        struct nfs_inode *nfsi = NFS_I(inode);
 
        spin_lock(&inode->i_lock);
-       nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
+       nfsi->cache_validity |= NFS_INO_INVALID_ATTR |
+                               NFS_INO_REVAL_PAGECACHE |
+                               NFS_INO_INVALID_ACCESS |
+                               NFS_INO_INVALID_ACL;
        if (S_ISDIR(inode->i_mode))
-               nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
+               nfsi->cache_validity |= NFS_INO_INVALID_DATA;
        spin_unlock(&inode->i_lock);
 }
 
index a2ea1491d3dfc487611445490fb10adf9972d777..20bc8e51b16124496326274e84fc12d61996a4fd 100644 (file)
@@ -220,7 +220,7 @@ struct nfs_server {
 #define NFS_CAP_SYMLINKS       (1U << 2)
 #define NFS_CAP_ACLS           (1U << 3)
 #define NFS_CAP_ATOMIC_OPEN    (1U << 4)
-#define NFS_CAP_CHANGE_ATTR    (1U << 5)
+/* #define NFS_CAP_CHANGE_ATTR (1U << 5) */
 #define NFS_CAP_FILEID         (1U << 6)
 #define NFS_CAP_MODE           (1U << 7)
 #define NFS_CAP_NLINK          (1U << 8)
index 4c508549833a53fc76b59ba6a0bda354fc4d051f..cc7dd687a89dd60699ebe28556138e293bcde9bc 100644 (file)
@@ -59,7 +59,7 @@ void of_dma_configure(struct device *dev, struct device_node *np);
 #else /* CONFIG_OF */
 
 static inline int of_driver_match_device(struct device *dev,
-                                        struct device_driver *drv)
+                                        const struct device_driver *drv)
 {
        return 0;
 }
index f34e040b34e9ffbf0abe66b439571ec8902440ca..41c93844fb1d1ed5c0dbad77fe5a409557d66067 100644 (file)
@@ -631,15 +631,19 @@ static inline void ClearPageSlabPfmemalloc(struct page *page)
         1 << PG_private | 1 << PG_private_2 | \
         1 << PG_writeback | 1 << PG_reserved | \
         1 << PG_slab    | 1 << PG_swapcache | 1 << PG_active | \
-        1 << PG_unevictable | __PG_MLOCKED | __PG_HWPOISON | \
+        1 << PG_unevictable | __PG_MLOCKED | \
         __PG_COMPOUND_LOCK)
 
 /*
  * Flags checked when a page is prepped for return by the page allocator.
- * Pages being prepped should not have any flags set.  It they are set,
+ * Pages being prepped should not have these flags set.  It they are set,
  * there has been a kernel bug or struct page corruption.
+ *
+ * __PG_HWPOISON is exceptional because it needs to be kept beyond page's
+ * alloc-free cycle to prevent from reusing the page.
  */
-#define PAGE_FLAGS_CHECK_AT_PREP       ((1 << NR_PAGEFLAGS) - 1)
+#define PAGE_FLAGS_CHECK_AT_PREP       \
+       (((1 << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON)
 
 #define PAGE_FLAGS_PRIVATE                             \
        (1 << PG_private | 1 << PG_private_2)
index 044a124bfbbc6b313d96f187a598fcb1438b8cc6..21b15f6fee2546e520a355b5a1d8cd4835fdc518 100644 (file)
@@ -8,11 +8,19 @@
 #ifndef __MACB_PDATA_H__
 #define __MACB_PDATA_H__
 
+/**
+ * struct macb_platform_data - platform data for MACB Ethernet
+ * @phy_mask:          phy mask passed when register the MDIO bus
+ *                     within the driver
+ * @phy_irq_pin:       PHY IRQ
+ * @is_rmii:           using RMII interface?
+ * @rev_eth_addr:      reverse Ethernet address byte order
+ */
 struct macb_platform_data {
        u32             phy_mask;
-       int             phy_irq_pin;    /* PHY IRQ */
-       u8              is_rmii;        /* using RMII interface? */
-       u8              rev_eth_addr;   /* reverse Ethernet address byte order */
+       int             phy_irq_pin;
+       u8              is_rmii;
+       u8              rev_eth_addr;
 };
 
 #endif /* __MACB_PDATA_H__ */
index 75f70f6ac13778f448a03de3136d32a0ef638b65..e1571efa3f2b28e01642e08f6709d7c7c8dc141a 100644 (file)
@@ -43,7 +43,6 @@ struct esdhc_platform_data {
        enum wp_types wp_type;
        enum cd_types cd_type;
        int max_bus_width;
-       unsigned int f_max;
        bool support_vsel;
        unsigned int delay_line;
 };
index d6cdd6e87d53bcd1b4f390f61f73b1c91b076bdd..22b6d9ca1654f15cb2d61b48a0ea531bc84b2d6e 100644 (file)
@@ -2884,11 +2884,11 @@ static inline bool skb_defer_rx_timestamp(struct sk_buff *skb)
  *
  * PHY drivers may accept clones of transmitted packets for
  * timestamping via their phy_driver.txtstamp method. These drivers
- * must call this function to return the skb back to the stack, with
- * or without a timestamp.
+ * must call this function to return the skb back to the stack with a
+ * timestamp.
  *
  * @skb: clone of the the original outgoing packet
- * @hwtstamps: hardware time stamps, may be NULL if not available
+ * @hwtstamps: hardware time stamps
  *
  */
 void skb_complete_tx_timestamp(struct sk_buff *skb,
index 3ee4c92afd1bd2baf2b90201a9b4af896d020b5f..931738bc5bba3c999ef280f1f68e9256bf445233 100644 (file)
@@ -99,7 +99,6 @@ struct tc_action_ops {
 
 int tcf_hash_search(struct tc_action *a, u32 index);
 void tcf_hash_destroy(struct tc_action *a);
-int tcf_hash_release(struct tc_action *a, int bind);
 u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo);
 int tcf_hash_check(u32 index, struct tc_action *a, int bind);
 int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
@@ -107,6 +106,13 @@ int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
 void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est);
 void tcf_hash_insert(struct tc_action *a);
 
+int __tcf_hash_release(struct tc_action *a, bool bind, bool strict);
+
+static inline int tcf_hash_release(struct tc_action *a, bool bind)
+{
+       return __tcf_hash_release(a, bind, false);
+}
+
 int tcf_register_action(struct tc_action_ops *a, unsigned int mask);
 int tcf_unregister_action(struct tc_action_ops *a);
 int tcf_action_destroy(struct list_head *actions, int bind);
index a741678f24a26d712e08775e213b1b1c50c8ca8a..883fe1e7c5a17e982651a68cfb17cbc0bbe5b367 100644 (file)
@@ -4868,6 +4868,23 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
                             struct cfg80211_chan_def *chandef,
                             enum nl80211_iftype iftype);
 
+/**
+ * cfg80211_reg_can_beacon_relax - check if beaconing is allowed with relaxation
+ * @wiphy: the wiphy
+ * @chandef: the channel definition
+ * @iftype: interface type
+ *
+ * Return: %true if there is no secondary channel or the secondary channel(s)
+ * can be used for beaconing (i.e. is not a radar channel etc.). This version
+ * also checks if IR-relaxation conditions apply, to allow beaconing under
+ * more permissive conditions.
+ *
+ * Requires the RTNL to be held.
+ */
+bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
+                                  struct cfg80211_chan_def *chandef,
+                                  enum nl80211_iftype iftype);
+
 /*
  * cfg80211_ch_switch_notify - update wdev channel and notify userspace
  * @dev: the device which switched channels
index e1300b3dd597b9a68db7b6dc9c03a8ea238b4e4c..53eead2da74324b47ef8c772663f9bcb4fd1d0e1 100644 (file)
@@ -21,13 +21,11 @@ struct netns_frags {
  * @INET_FRAG_FIRST_IN: first fragment has arrived
  * @INET_FRAG_LAST_IN: final fragment has arrived
  * @INET_FRAG_COMPLETE: frag queue has been processed and is due for destruction
- * @INET_FRAG_EVICTED: frag queue is being evicted
  */
 enum {
        INET_FRAG_FIRST_IN      = BIT(0),
        INET_FRAG_LAST_IN       = BIT(1),
        INET_FRAG_COMPLETE      = BIT(2),
-       INET_FRAG_EVICTED       = BIT(3)
 };
 
 /**
@@ -45,6 +43,7 @@ enum {
  * @flags: fragment queue flags
  * @max_size: maximum received fragment size
  * @net: namespace that this frag belongs to
+ * @list_evictor: list of queues to forcefully evict (e.g. due to low memory)
  */
 struct inet_frag_queue {
        spinlock_t              lock;
@@ -59,6 +58,7 @@ struct inet_frag_queue {
        __u8                    flags;
        u16                     max_size;
        struct netns_frags      *net;
+       struct hlist_node       list_evictor;
 };
 
 #define INETFRAGS_HASHSZ       1024
@@ -125,6 +125,11 @@ static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f
                inet_frag_destroy(q, f);
 }
 
+static inline bool inet_frag_evicting(struct inet_frag_queue *q)
+{
+       return !hlist_unhashed(&q->list_evictor);
+}
+
 /* Memory Tracking Functions. */
 
 /* The default percpu_counter batch size is not big enough to scale to
@@ -139,14 +144,14 @@ static inline int frag_mem_limit(struct netns_frags *nf)
        return percpu_counter_read(&nf->mem);
 }
 
-static inline void sub_frag_mem_limit(struct inet_frag_queue *q, int i)
+static inline void sub_frag_mem_limit(struct netns_frags *nf, int i)
 {
-       __percpu_counter_add(&q->net->mem, -i, frag_percpu_counter_batch);
+       __percpu_counter_add(&nf->mem, -i, frag_percpu_counter_batch);
 }
 
-static inline void add_frag_mem_limit(struct inet_frag_queue *q, int i)
+static inline void add_frag_mem_limit(struct netns_frags *nf, int i)
 {
-       __percpu_counter_add(&q->net->mem, i, frag_percpu_counter_batch);
+       __percpu_counter_add(&nf->mem, i, frag_percpu_counter_batch);
 }
 
 static inline void init_frag_mem_limit(struct netns_frags *nf)
index 0750a186ea635678efe15b2619f32e91f86fde99..d5fe9f2ab6996f0aa9482980ecc4cdc793d63a5a 100644 (file)
@@ -161,6 +161,7 @@ static inline __u8 get_rtconn_flags(struct ipcm_cookie* ipc, struct sock* sk)
 }
 
 /* datagram.c */
+int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
 int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
 
 void ip4_datagram_release_cb(struct sock *sk);
index 49c142bdf01e67b55bcf59c2d1e63f6615783ea1..5fa643b4e8913a35b3a3ead9ad66fa74d368ef70 100644 (file)
@@ -183,7 +183,6 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh);
 struct fib_table {
        struct hlist_node       tb_hlist;
        u32                     tb_id;
-       int                     tb_default;
        int                     tb_num_default;
        struct rcu_head         rcu;
        unsigned long           *tb_data;
@@ -290,7 +289,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb);
 int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
                        u8 tos, int oif, struct net_device *dev,
                        struct in_device *idev, u32 *itag);
-void fib_select_default(struct fib_result *res);
+void fib_select_default(const struct flowi4 *flp, struct fib_result *res);
 #ifdef CONFIG_IP_ROUTE_CLASSID
 static inline int fib_num_tclassid_users(struct net *net)
 {
index 095433b8a8b03dec4b99057dd7165c9dc6d7846f..37cd3911d5c59e97fe6328a2852ea17040f4dbc3 100644 (file)
@@ -291,7 +291,7 @@ extern unsigned int nf_conntrack_max;
 extern unsigned int nf_conntrack_hash_rnd;
 void init_nf_conntrack_hash_rnd(void);
 
-void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl);
+struct nf_conn *nf_ct_tmpl_alloc(struct net *net, u16 zone, gfp_t flags);
 
 #define NF_CT_STAT_INC(net, count)       __this_cpu_inc((net)->ct.stat->count)
 #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count)
index 29d6a94db54d6136b6b380d5817341d2bbe83bce..723b61c82b3f444aee0e7591b8028cb2548e228e 100644 (file)
@@ -68,7 +68,6 @@ struct ct_pcpu {
        spinlock_t              lock;
        struct hlist_nulls_head unconfirmed;
        struct hlist_nulls_head dying;
-       struct hlist_nulls_head tmpl;
 };
 
 struct netns_ct {
index 05a8c1aea25187c1692efcb1e350bb2c7f75a30b..f21f0708ec59ab6fa186657aaa15380590b061f2 100644 (file)
@@ -902,7 +902,7 @@ void sk_stream_kill_queues(struct sock *sk);
 void sk_set_memalloc(struct sock *sk);
 void sk_clear_memalloc(struct sock *sk);
 
-int sk_wait_data(struct sock *sk, long *timeo);
+int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb);
 
 struct request_sock_ops;
 struct timewait_sock_ops;
index 34117b8b72e49d84fb9477326ad10a490de1060a..0aedbb2c10e0451c162118988d6c070efcd9b629 100644 (file)
@@ -595,6 +595,7 @@ struct iscsi_conn {
        int                     bitmap_id;
        int                     rx_thread_active;
        struct task_struct      *rx_thread;
+       struct completion       rx_login_comp;
        int                     tx_thread_active;
        struct task_struct      *tx_thread;
        /* list_head for session connection list */
index b6fce900a8334613f45f169a0c28802327222f56..fbdd11851725ffa77435b0d3f66cfdfd4f7bb5fb 100644 (file)
@@ -32,7 +32,7 @@
 #ifndef __AMDGPU_DRM_H__
 #define __AMDGPU_DRM_H__
 
-#include <drm/drm.h>
+#include "drm.h"
 
 #define DRM_AMDGPU_GEM_CREATE          0x00
 #define DRM_AMDGPU_GEM_MMAP            0x01
@@ -614,6 +614,8 @@ struct drm_amdgpu_info_device {
        uint32_t vram_type;
        /** video memory bit width*/
        uint32_t vram_bit_width;
+       /* vce harvesting instance */
+       uint32_t vce_harvest_config;
 };
 
 struct drm_amdgpu_info_hw_ip {
index 192027b4f0314a14e41b589b45fd4e80d8089ab9..dbd16a2d37db6defcadf264d5f5a5b474d819be2 100644 (file)
@@ -1081,6 +1081,14 @@ struct drm_i915_reg_read {
        __u64 offset;
        __u64 val; /* Return value */
 };
+/* Known registers:
+ *
+ * Render engine timestamp - 0x2358 + 64bit - gen7+
+ * - Note this register returns an invalid value if using the default
+ *   single instruction 8byte read, in order to workaround that use
+ *   offset (0x2538 | 1) instead.
+ *
+ */
 
 struct drm_i915_reset_stats {
        __u32 ctx_id;
index 1ef76661e1a1b5cc7a1d1021aefd2501f8e5375e..01aa2a8e3f8de1bc368ab53f3f5db472f0329fa7 100644 (file)
@@ -33,7 +33,7 @@
 #ifndef __RADEON_DRM_H__
 #define __RADEON_DRM_H__
 
-#include <drm/drm.h>
+#include "drm.h"
 
 /* WARNING: If you change any of these defines, make sure to change the
  * defines in the X server file (radeon_sarea.h)
index efe3443572baa5a3650d638806fd60ef09a90f68..413417f3707bbfde6375dfc14098bc1e099b5b70 100644 (file)
 #define PCI_MSIX_PBA           8       /* Pending Bit Array offset */
 #define  PCI_MSIX_PBA_BIR      0x00000007 /* BAR index */
 #define  PCI_MSIX_PBA_OFFSET   0xfffffff8 /* Offset into specified BAR */
+#define PCI_MSIX_FLAGS_BIRMASK PCI_MSIX_PBA_BIR /* deprecated */
 #define PCI_CAP_MSIX_SIZEOF    12      /* size of MSIX registers */
 
 /* MSI-X Table entry format */
index 7bbee79ca2933f518a16f0250e7bbfd0a4e85fe0..ec32293a00db057eb7559c2e7cadce01deb3ef22 100644 (file)
@@ -34,6 +34,7 @@
 /* The feature bitmap for virtio net */
 #define VIRTIO_NET_F_CSUM      0       /* Host handles pkts w/ partial csum */
 #define VIRTIO_NET_F_GUEST_CSUM        1       /* Guest handles pkts w/ partial csum */
+#define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS 2 /* Dynamic offload configuration. */
 #define VIRTIO_NET_F_MAC       5       /* Host has given MAC address. */
 #define VIRTIO_NET_F_GUEST_TSO4        7       /* Guest can handle TSOv4 in. */
 #define VIRTIO_NET_F_GUEST_TSO6        8       /* Guest can handle TSOv6 in. */
@@ -226,4 +227,19 @@ struct virtio_net_ctrl_mq {
  #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN        1
  #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX        0x8000
 
+/*
+ * Control network offloads
+ *
+ * Reconfigures the network offloads that Guest can handle.
+ *
+ * Available with the VIRTIO_NET_F_CTRL_GUEST_OFFLOADS feature bit.
+ *
+ * Command data format matches the feature bit mask exactly.
+ *
+ * See VIRTIO_NET_F_GUEST_* for the list of offloads
+ * that can be enabled/disabled.
+ */
+#define VIRTIO_NET_CTRL_GUEST_OFFLOADS   5
+#define VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET        0
+
 #endif /* _LINUX_VIRTIO_NET_H */
index 75301468359f0c558ff8c3c12450301c80cff19a..90007a1abcab144ac3d6ac7d6e6f4001d58abb14 100644 (file)
@@ -157,6 +157,12 @@ struct virtio_pci_common_cfg {
        __le32 queue_used_hi;           /* read-write */
 };
 
+/* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
+struct virtio_pci_cfg_cap {
+       struct virtio_pci_cap cap;
+       __u8 pci_cfg_data[4]; /* Data for BAR access. */
+};
+
 /* Macro versions of offsets for the Old Timers! */
 #define VIRTIO_PCI_CAP_VNDR            0
 #define VIRTIO_PCI_CAP_NEXT            1
index 915980ac68dfa8cc1dc973b8a7e659fc56383c22..c07295969b7e134ec85bf58b72b100949a6462fa 100644 (file)
@@ -31,6 +31,9 @@
  * SUCH DAMAGE.
  *
  * Copyright Rusty Russell IBM Corporation 2007. */
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
 #include <linux/types.h>
 #include <linux/virtio_types.h>
 
@@ -143,7 +146,7 @@ static inline void vring_init(struct vring *vr, unsigned int num, void *p,
        vr->num = num;
        vr->desc = p;
        vr->avail = p + num*sizeof(struct vring_desc);
-       vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(__virtio16)
+       vr->used = (void *)(((uintptr_t)&vr->avail->ring[num] + sizeof(__virtio16)
                + align-1) & ~(align - 1));
 }
 
index 12215205ab8d0b11d854dcaa29f00bed48a980c7..51b8066a223b504ebf14ec287da3e56109a0e674 100644 (file)
@@ -77,7 +77,7 @@
 #define SND_SOC_TPLG_NUM_TEXTS         16
 
 /* ABI version */
-#define SND_SOC_TPLG_ABI_VERSION       0x2
+#define SND_SOC_TPLG_ABI_VERSION       0x3
 
 /* Max size of TLV data */
 #define SND_SOC_TPLG_TLV_SIZE          32
@@ -97,7 +97,8 @@
 #define SND_SOC_TPLG_TYPE_PCM          7
 #define SND_SOC_TPLG_TYPE_MANIFEST     8
 #define SND_SOC_TPLG_TYPE_CODEC_LINK   9
-#define SND_SOC_TPLG_TYPE_MAX  SND_SOC_TPLG_TYPE_CODEC_LINK
+#define SND_SOC_TPLG_TYPE_PDATA                10
+#define SND_SOC_TPLG_TYPE_MAX  SND_SOC_TPLG_TYPE_PDATA
 
 /* vendor block IDs - please add new vendor types to end */
 #define SND_SOC_TPLG_TYPE_VENDOR_FW    1000
 
 /*
  * Block Header.
- * This header preceeds all object and object arrays below.
+ * This header precedes all object and object arrays below.
  */
 struct snd_soc_tplg_hdr {
        __le32 magic;           /* magic number */
@@ -137,11 +138,19 @@ struct snd_soc_tplg_private {
 /*
  * Kcontrol TLV data.
  */
+struct snd_soc_tplg_tlv_dbscale {
+       __le32 min;
+       __le32 step;
+       __le32 mute;
+} __attribute__((packed));
+
 struct snd_soc_tplg_ctl_tlv {
-       __le32 size;    /* in bytes aligned to 4 */
-       __le32 numid;   /* control element numeric identification */
-       __le32 count;   /* number of elem in data array */
-       __le32 data[SND_SOC_TPLG_TLV_SIZE];
+       __le32 size;    /* in bytes of this structure */
+       __le32 type;    /* SNDRV_CTL_TLVT_*, type of TLV */
+       union {
+               __le32 data[SND_SOC_TPLG_TLV_SIZE];
+               struct snd_soc_tplg_tlv_dbscale scale;
+       };
 } __attribute__((packed));
 
 /*
@@ -155,9 +164,11 @@ struct snd_soc_tplg_channel {
 } __attribute__((packed));
 
 /*
- * Kcontrol Operations IDs
+ * Genericl Operations IDs, for binding Kcontrol or Bytes ext ops
+ * Kcontrol ops need get/put/info.
+ * Bytes ext ops need get/put.
  */
-struct snd_soc_tplg_kcontrol_ops_id {
+struct snd_soc_tplg_io_ops {
        __le32 get;
        __le32 put;
        __le32 info;
@@ -171,8 +182,8 @@ struct snd_soc_tplg_ctl_hdr {
        __le32 type;
        char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        __le32 access;
-       struct snd_soc_tplg_kcontrol_ops_id ops;
-       __le32 tlv_size;        /* non zero means control has TLV data */
+       struct snd_soc_tplg_io_ops ops;
+       struct snd_soc_tplg_ctl_tlv tlv;
 } __attribute__((packed));
 
 /*
@@ -222,7 +233,7 @@ struct snd_soc_tplg_stream_config {
 /*
  * Manifest. List totals for each payload type. Not used in parsing, but will
  * be passed to the component driver before any other objects in order for any
- * global componnent resource allocations.
+ * global component resource allocations.
  *
  * File block representation for manifest :-
  * +-----------------------------------+----+
@@ -238,6 +249,7 @@ struct snd_soc_tplg_manifest {
        __le32 graph_elems;     /* number of graph elements */
        __le32 dai_elems;       /* number of DAI elements */
        __le32 dai_link_elems;  /* number of DAI link elements */
+       struct snd_soc_tplg_private priv;
 } __attribute__((packed));
 
 /*
@@ -259,7 +271,6 @@ struct snd_soc_tplg_mixer_control {
        __le32 invert;
        __le32 num_channels;
        struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
-       struct snd_soc_tplg_ctl_tlv tlv;
        struct snd_soc_tplg_private priv;
 } __attribute__((packed));
 
@@ -303,6 +314,7 @@ struct snd_soc_tplg_bytes_control {
        __le32 mask;
        __le32 base;
        __le32 num_regs;
+       struct snd_soc_tplg_io_ops ext_ops;
        struct snd_soc_tplg_private priv;
 } __attribute__((packed));
 
@@ -347,6 +359,7 @@ struct snd_soc_tplg_dapm_widget {
        __le32 reg;             /* negative reg = no direct dapm */
        __le32 shift;           /* bits to shift */
        __le32 mask;            /* non-shifted mask */
+       __le32 subseq;          /* sort within widget type */
        __u32 invert;           /* invert the power bit */
        __u32 ignore_suspend;   /* kept enabled over suspend */
        __u16 event_flags;
index c5d5626289cee3a46f7e1b7d2441ca0496ba4471..56506553d4d80dff814b75f45db6db280fd0dea7 100644 (file)
@@ -656,7 +656,7 @@ asmlinkage __visible void __init start_kernel(void)
        key_init();
        security_init();
        dbg_late_init();
-       vfs_caches_init(totalram_pages);
+       vfs_caches_init();
        signals_init();
        /* rootfs populating might need page-writeback */
        page_writeback_init();
index a24ba9fe5bb8892dfaa7452fe78f9ef68d1d97fc..161a1807e6efb0fe8e773c41dafc8b4a76b38f71 100644 (file)
@@ -142,7 +142,6 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
                if (!leaf)
                        return -ENOMEM;
                INIT_LIST_HEAD(&leaf->msg_list);
-               info->qsize += sizeof(*leaf);
        }
        leaf->priority = msg->m_type;
        rb_link_node(&leaf->rb_node, parent, p);
@@ -187,7 +186,6 @@ try_again:
                             "lazy leaf delete!\n");
                rb_erase(&leaf->rb_node, &info->msg_tree);
                if (info->node_cache) {
-                       info->qsize -= sizeof(*leaf);
                        kfree(leaf);
                } else {
                        info->node_cache = leaf;
@@ -200,7 +198,6 @@ try_again:
                if (list_empty(&leaf->msg_list)) {
                        rb_erase(&leaf->rb_node, &info->msg_tree);
                        if (info->node_cache) {
-                               info->qsize -= sizeof(*leaf);
                                kfree(leaf);
                        } else {
                                info->node_cache = leaf;
@@ -1034,7 +1031,6 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
                /* Save our speculative allocation into the cache */
                INIT_LIST_HEAD(&new_leaf->msg_list);
                info->node_cache = new_leaf;
-               info->qsize += sizeof(*new_leaf);
                new_leaf = NULL;
        } else {
                kfree(new_leaf);
@@ -1142,7 +1138,6 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
                /* Save our speculative allocation into the cache */
                INIT_LIST_HEAD(&new_leaf->msg_list);
                info->node_cache = new_leaf;
-               info->qsize += sizeof(*new_leaf);
        } else {
                kfree(new_leaf);
        }
index bc3d530cb23efacb2e5695ad85a9bd3898524fa2..b471e5a3863ddbca70f2bf4dee22f40df0345fbe 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -252,6 +252,16 @@ static void sem_rcu_free(struct rcu_head *head)
        ipc_rcu_free(head);
 }
 
+/*
+ * spin_unlock_wait() and !spin_is_locked() are not memory barriers, they
+ * are only control barriers.
+ * The code must pair with spin_unlock(&sem->lock) or
+ * spin_unlock(&sem_perm.lock), thus just the control barrier is insufficient.
+ *
+ * smp_rmb() is sufficient, as writes cannot pass the control barrier.
+ */
+#define ipc_smp_acquire__after_spin_is_unlocked()      smp_rmb()
+
 /*
  * Wait until all currently ongoing simple ops have completed.
  * Caller must own sem_perm.lock.
@@ -275,6 +285,7 @@ static void sem_wait_array(struct sem_array *sma)
                sem = sma->sem_base + i;
                spin_unlock_wait(&sem->lock);
        }
+       ipc_smp_acquire__after_spin_is_unlocked();
 }
 
 /*
@@ -327,13 +338,12 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
                /* Then check that the global lock is free */
                if (!spin_is_locked(&sma->sem_perm.lock)) {
                        /*
-                        * The ipc object lock check must be visible on all
-                        * cores before rechecking the complex count.  Otherwise
-                        * we can race with  another thread that does:
+                        * We need a memory barrier with acquire semantics,
+                        * otherwise we can race with another thread that does:
                         *      complex_count++;
                         *      spin_unlock(sem_perm.lock);
                         */
-                       smp_rmb();
+                       ipc_smp_acquire__after_spin_is_unlocked();
 
                        /*
                         * Now repeat the test of complex_count:
@@ -2074,17 +2084,28 @@ void exit_sem(struct task_struct *tsk)
                rcu_read_lock();
                un = list_entry_rcu(ulp->list_proc.next,
                                    struct sem_undo, list_proc);
-               if (&un->list_proc == &ulp->list_proc)
-                       semid = -1;
-                else
-                       semid = un->semid;
+               if (&un->list_proc == &ulp->list_proc) {
+                       /*
+                        * We must wait for freeary() before freeing this ulp,
+                        * in case we raced with last sem_undo. There is a small
+                        * possibility where we exit while freeary() didn't
+                        * finish unlocking sem_undo_list.
+                        */
+                       spin_unlock_wait(&ulp->lock);
+                       rcu_read_unlock();
+                       break;
+               }
+               spin_lock(&ulp->lock);
+               semid = un->semid;
+               spin_unlock(&ulp->lock);
 
+               /* exit_sem raced with IPC_RMID, nothing to do */
                if (semid == -1) {
                        rcu_read_unlock();
-                       break;
+                       continue;
                }
 
-               sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, un->semid);
+               sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, semid);
                /* exit_sem raced with IPC_RMID, nothing to do */
                if (IS_ERR(sma)) {
                        rcu_read_unlock();
@@ -2112,9 +2133,11 @@ void exit_sem(struct task_struct *tsk)
                ipc_assert_locked_object(&sma->sem_perm);
                list_del(&un->list_id);
 
-               spin_lock(&ulp->lock);
+               /* we are the last process using this ulp, acquiring ulp->lock
+                * isn't required. Besides that, we are also protected against
+                * IPC_RMID as we hold sma->sem_perm lock now
+                */
                list_del_rcu(&un->list_proc);
-               spin_unlock(&ulp->lock);
 
                /* perform adjustments registered in un */
                for (i = 0; i < sma->sem_nsems; i++) {
index 06e5cf2fe019faee43aa9f8ca9f17cad4973b74d..4aef24d91b633e12275cea64a380df4543fc796b 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -545,7 +545,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
                if  ((shmflg & SHM_NORESERVE) &&
                                sysctl_overcommit_memory != OVERCOMMIT_NEVER)
                        acctflag = VM_NORESERVE;
-               file = shmem_file_setup(name, size, acctflag);
+               file = shmem_kernel_file_setup(name, size, acctflag);
        }
        error = PTR_ERR(file);
        if (IS_ERR(file))
index d3dae3419b99566c127f1682b29f39bb184bbdb1..e6feb51141340a99a248fea0ad1dc17402b0dbdb 100644 (file)
@@ -1868,8 +1868,6 @@ event_sched_in(struct perf_event *event,
 
        perf_pmu_disable(event->pmu);
 
-       event->tstamp_running += tstamp - event->tstamp_stopped;
-
        perf_set_shadow_time(event, ctx, tstamp);
 
        perf_log_itrace_start(event);
@@ -1881,6 +1879,8 @@ event_sched_in(struct perf_event *event,
                goto out;
        }
 
+       event->tstamp_running += tstamp - event->tstamp_stopped;
+
        if (!is_software_event(event))
                cpuctx->active_oncpu++;
        if (!ctx->nr_active++)
@@ -3958,28 +3958,21 @@ static void perf_event_for_each(struct perf_event *event,
                perf_event_for_each_child(sibling, func);
 }
 
-static int perf_event_period(struct perf_event *event, u64 __user *arg)
-{
-       struct perf_event_context *ctx = event->ctx;
-       int ret = 0, active;
+struct period_event {
+       struct perf_event *event;
        u64 value;
+};
 
-       if (!is_sampling_event(event))
-               return -EINVAL;
-
-       if (copy_from_user(&value, arg, sizeof(value)))
-               return -EFAULT;
-
-       if (!value)
-               return -EINVAL;
+static int __perf_event_period(void *info)
+{
+       struct period_event *pe = info;
+       struct perf_event *event = pe->event;
+       struct perf_event_context *ctx = event->ctx;
+       u64 value = pe->value;
+       bool active;
 
-       raw_spin_lock_irq(&ctx->lock);
+       raw_spin_lock(&ctx->lock);
        if (event->attr.freq) {
-               if (value > sysctl_perf_event_sample_rate) {
-                       ret = -EINVAL;
-                       goto unlock;
-               }
-
                event->attr.sample_freq = value;
        } else {
                event->attr.sample_period = value;
@@ -3998,11 +3991,53 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
                event->pmu->start(event, PERF_EF_RELOAD);
                perf_pmu_enable(ctx->pmu);
        }
+       raw_spin_unlock(&ctx->lock);
 
-unlock:
+       return 0;
+}
+
+static int perf_event_period(struct perf_event *event, u64 __user *arg)
+{
+       struct period_event pe = { .event = event, };
+       struct perf_event_context *ctx = event->ctx;
+       struct task_struct *task;
+       u64 value;
+
+       if (!is_sampling_event(event))
+               return -EINVAL;
+
+       if (copy_from_user(&value, arg, sizeof(value)))
+               return -EFAULT;
+
+       if (!value)
+               return -EINVAL;
+
+       if (event->attr.freq && value > sysctl_perf_event_sample_rate)
+               return -EINVAL;
+
+       task = ctx->task;
+       pe.value = value;
+
+       if (!task) {
+               cpu_function_call(event->cpu, __perf_event_period, &pe);
+               return 0;
+       }
+
+retry:
+       if (!task_function_call(task, __perf_event_period, &pe))
+               return 0;
+
+       raw_spin_lock_irq(&ctx->lock);
+       if (ctx->is_active) {
+               raw_spin_unlock_irq(&ctx->lock);
+               task = ctx->task;
+               goto retry;
+       }
+
+       __perf_event_period(&pe);
        raw_spin_unlock_irq(&ctx->lock);
 
-       return ret;
+       return 0;
 }
 
 static const struct file_operations perf_fops;
@@ -4740,12 +4775,20 @@ static const struct file_operations perf_fops = {
  * to user-space before waking everybody up.
  */
 
+static inline struct fasync_struct **perf_event_fasync(struct perf_event *event)
+{
+       /* only the parent has fasync state */
+       if (event->parent)
+               event = event->parent;
+       return &event->fasync;
+}
+
 void perf_event_wakeup(struct perf_event *event)
 {
        ring_buffer_wakeup(event);
 
        if (event->pending_kill) {
-               kill_fasync(&event->fasync, SIGIO, event->pending_kill);
+               kill_fasync(perf_event_fasync(event), SIGIO, event->pending_kill);
                event->pending_kill = 0;
        }
 }
@@ -6124,7 +6167,7 @@ static int __perf_event_overflow(struct perf_event *event,
        else
                perf_event_output(event, data, regs);
 
-       if (event->fasync && event->pending_kill) {
+       if (*perf_event_fasync(event) && event->pending_kill) {
                event->pending_wakeup = 1;
                irq_work_queue(&event->pending);
        }
index b2be01b1aa9dcb7a70792fa381c264b229a106d0..c8aa3f75bc4db8ad7a2242aae6406bfd6f86f8c5 100644 (file)
@@ -559,11 +559,13 @@ static void __rb_free_aux(struct ring_buffer *rb)
                rb->aux_priv = NULL;
        }
 
-       for (pg = 0; pg < rb->aux_nr_pages; pg++)
-               rb_free_aux_page(rb, pg);
+       if (rb->aux_nr_pages) {
+               for (pg = 0; pg < rb->aux_nr_pages; pg++)
+                       rb_free_aux_page(rb, pg);
 
-       kfree(rb->aux_pages);
-       rb->aux_nr_pages = 0;
+               kfree(rb->aux_pages);
+               rb->aux_nr_pages = 0;
+       }
 }
 
 void rb_free_aux(struct ring_buffer *rb)
index 10e489c448fe4e934e2c203ca2aa7a8d0679bb5e..fdea0bee7b5a4d5e2fcf43ee3b92e1a37dea6c71 100644 (file)
@@ -97,6 +97,7 @@ bool kthread_should_park(void)
 {
        return test_bit(KTHREAD_SHOULD_PARK, &to_kthread(current)->flags);
 }
+EXPORT_SYMBOL_GPL(kthread_should_park);
 
 /**
  * kthread_freezable_should_stop - should this freezable kthread return now?
@@ -171,6 +172,7 @@ void kthread_parkme(void)
 {
        __kthread_parkme(to_kthread(current));
 }
+EXPORT_SYMBOL_GPL(kthread_parkme);
 
 static int kthread(void *_create)
 {
@@ -411,6 +413,7 @@ void kthread_unpark(struct task_struct *k)
        if (kthread)
                __kthread_unpark(k, kthread);
 }
+EXPORT_SYMBOL_GPL(kthread_unpark);
 
 /**
  * kthread_park - park a thread created by kthread_create().
@@ -441,6 +444,7 @@ int kthread_park(struct task_struct *k)
        }
        return ret;
 }
+EXPORT_SYMBOL_GPL(kthread_park);
 
 /**
  * kthread_stop - stop a thread created by kthread_create().
index 04ab18151cc8fa174a5859124ee07c144f33d505..df19ae4debd09c134d438b57e4ead7c71462c2b6 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/hash.h>
 #include <linux/bootmem.h>
+#include <linux/debug_locks.h>
 
 /*
  * Implement paravirt qspinlocks; the general idea is to halt the vcpus instead
@@ -286,15 +287,23 @@ __visible void __pv_queued_spin_unlock(struct qspinlock *lock)
 {
        struct __qspinlock *l = (void *)lock;
        struct pv_node *node;
+       u8 lockval = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0);
 
        /*
         * We must not unlock if SLOW, because in that case we must first
         * unhash. Otherwise it would be possible to have multiple @lock
         * entries, which would be BAD.
         */
-       if (likely(cmpxchg(&l->locked, _Q_LOCKED_VAL, 0) == _Q_LOCKED_VAL))
+       if (likely(lockval == _Q_LOCKED_VAL))
                return;
 
+       if (unlikely(lockval != _Q_SLOW_VAL)) {
+               if (debug_locks_silent)
+                       return;
+               WARN(1, "pvqspinlock: lock %p has corrupted value 0x%x!\n", lock, atomic_read(&lock->val));
+               return;
+       }
+
        /*
         * Since the above failed to release, this must be the SLOW path.
         * Therefore start by looking up the blocked node and unhashing it.
index 4d2b82e610e2a48f429a700f0529d6dc5942700a..b86b7bf1be388d72fe92fb6038b4a67b4710df1f 100644 (file)
@@ -602,13 +602,16 @@ const struct kernel_symbol *find_symbol(const char *name,
 }
 EXPORT_SYMBOL_GPL(find_symbol);
 
-/* Search for module by name: must hold module_mutex. */
+/*
+ * Search for module by name: must hold module_mutex (or preempt disabled
+ * for read-only access).
+ */
 static struct module *find_module_all(const char *name, size_t len,
                                      bool even_unformed)
 {
        struct module *mod;
 
-       module_assert_mutex();
+       module_assert_mutex_or_preempt();
 
        list_for_each_entry(mod, &modules, list) {
                if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
@@ -621,6 +624,7 @@ static struct module *find_module_all(const char *name, size_t len,
 
 struct module *find_module(const char *name)
 {
+       module_assert_mutex();
        return find_module_all(name, strlen(name), false);
 }
 EXPORT_SYMBOL_GPL(find_module);
index 90552aab5f2dd076c147c73cc6f9ff59aabb7af6..fed052a1bc9f5792c7cb856336f2093e75aa2432 100644 (file)
@@ -504,13 +504,13 @@ int region_is_ram(resource_size_t start, unsigned long size)
 {
        struct resource *p;
        resource_size_t end = start + size - 1;
-       int flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+       unsigned long flags = IORESOURCE_MEM | IORESOURCE_BUSY;
        const char *name = "System RAM";
        int ret = -1;
 
        read_lock(&resource_lock);
        for (p = iomem_resource.child; p ; p = p->sibling) {
-               if (end < p->start)
+               if (p->end < start)
                        continue;
 
                if (p->start <= start && end <= p->end) {
@@ -521,7 +521,7 @@ int region_is_ram(resource_size_t start, unsigned long size)
                                ret = 1;
                        break;
                }
-               if (p->end < start)
+               if (end < p->start)
                        break;  /* not found */
        }
        read_unlock(&resource_lock);
index 836df8dac6ccd1230f21d20dc610429538cc59a1..0f6bbbe77b46c092d0de31e0c9eec8a0f17e6791 100644 (file)
@@ -2748,12 +2748,15 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitly for the right codes here.
                 */
-               if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+               if (from->si_signo == SIGBUS &&
+                   (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
                        err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
 #endif
 #ifdef SEGV_BNDERR
-               err |= __put_user(from->si_lower, &to->si_lower);
-               err |= __put_user(from->si_upper, &to->si_upper);
+               if (from->si_signo == SIGSEGV && from->si_code == SEGV_BNDERR) {
+                       err |= __put_user(from->si_lower, &to->si_lower);
+                       err |= __put_user(from->si_upper, &to->si_upper);
+               }
 #endif
                break;
        case __SI_CHLD:
@@ -3017,7 +3020,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo,
                        int, sig,
                        struct compat_siginfo __user *, uinfo)
 {
-       siginfo_t info;
+       siginfo_t info = {};
        int ret = copy_siginfo_from_user32(&info, uinfo);
        if (unlikely(ret))
                return ret;
@@ -3061,7 +3064,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
                        int, sig,
                        struct compat_siginfo __user *, uinfo)
 {
-       siginfo_t info;
+       siginfo_t info = {};
 
        if (copy_siginfo_from_user32(&info, uinfo))
                return -EFAULT;
index 02bece4a99ea36bb835fc45a9aa55c1aedd69f9f..eb11011b5292add880af7038800560aa29c5a674 100644 (file)
@@ -98,6 +98,13 @@ struct ftrace_pid {
        struct pid *pid;
 };
 
+static bool ftrace_pids_enabled(void)
+{
+       return !list_empty(&ftrace_pids);
+}
+
+static void ftrace_update_trampoline(struct ftrace_ops *ops);
+
 /*
  * ftrace_disabled is set when an anomaly is discovered.
  * ftrace_disabled is much stronger than ftrace_enabled.
@@ -109,7 +116,6 @@ static DEFINE_MUTEX(ftrace_lock);
 static struct ftrace_ops *ftrace_control_list __read_mostly = &ftrace_list_end;
 static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end;
 ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
-ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;
 static struct ftrace_ops global_ops;
 static struct ftrace_ops control_ops;
 
@@ -183,14 +189,7 @@ static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip,
        if (!test_tsk_trace_trace(current))
                return;
 
-       ftrace_pid_function(ip, parent_ip, op, regs);
-}
-
-static void set_ftrace_pid_function(ftrace_func_t func)
-{
-       /* do not set ftrace_pid_function to itself! */
-       if (func != ftrace_pid_func)
-               ftrace_pid_function = func;
+       op->saved_func(ip, parent_ip, op, regs);
 }
 
 /**
@@ -202,7 +201,6 @@ static void set_ftrace_pid_function(ftrace_func_t func)
 void clear_ftrace_function(void)
 {
        ftrace_trace_function = ftrace_stub;
-       ftrace_pid_function = ftrace_stub;
 }
 
 static void control_ops_disable_all(struct ftrace_ops *ops)
@@ -436,6 +434,12 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
        } else
                add_ftrace_ops(&ftrace_ops_list, ops);
 
+       /* Always save the function, and reset at unregistering */
+       ops->saved_func = ops->func;
+
+       if (ops->flags & FTRACE_OPS_FL_PID && ftrace_pids_enabled())
+               ops->func = ftrace_pid_func;
+
        ftrace_update_trampoline(ops);
 
        if (ftrace_enabled)
@@ -463,15 +467,28 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
        if (ftrace_enabled)
                update_ftrace_function();
 
+       ops->func = ops->saved_func;
+
        return 0;
 }
 
 static void ftrace_update_pid_func(void)
 {
+       bool enabled = ftrace_pids_enabled();
+       struct ftrace_ops *op;
+
        /* Only do something if we are tracing something */
        if (ftrace_trace_function == ftrace_stub)
                return;
 
+       do_for_each_ftrace_op(op, ftrace_ops_list) {
+               if (op->flags & FTRACE_OPS_FL_PID) {
+                       op->func = enabled ? ftrace_pid_func :
+                               op->saved_func;
+                       ftrace_update_trampoline(op);
+               }
+       } while_for_each_ftrace_op(op);
+
        update_ftrace_function();
 }
 
@@ -1133,7 +1150,8 @@ static struct ftrace_ops global_ops = {
        .local_hash.filter_hash         = EMPTY_HASH,
        INIT_OPS_HASH(global_ops)
        .flags                          = FTRACE_OPS_FL_RECURSION_SAFE |
-                                         FTRACE_OPS_FL_INITIALIZED,
+                                         FTRACE_OPS_FL_INITIALIZED |
+                                         FTRACE_OPS_FL_PID,
 };
 
 /*
@@ -5023,7 +5041,9 @@ static void ftrace_update_trampoline(struct ftrace_ops *ops)
 
 static struct ftrace_ops global_ops = {
        .func                   = ftrace_stub,
-       .flags                  = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
+       .flags                  = FTRACE_OPS_FL_RECURSION_SAFE |
+                                 FTRACE_OPS_FL_INITIALIZED |
+                                 FTRACE_OPS_FL_PID,
 };
 
 static int __init ftrace_nodyn_init(void)
@@ -5080,11 +5100,6 @@ void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func)
                if (WARN_ON(tr->ops->func != ftrace_stub))
                        printk("ftrace ops had %pS for function\n",
                               tr->ops->func);
-               /* Only the top level instance does pid tracing */
-               if (!list_empty(&ftrace_pids)) {
-                       set_ftrace_pid_function(func);
-                       func = ftrace_pid_func;
-               }
        }
        tr->ops->func = func;
        tr->ops->private = tr;
@@ -5371,7 +5386,7 @@ static void *fpid_start(struct seq_file *m, loff_t *pos)
 {
        mutex_lock(&ftrace_lock);
 
-       if (list_empty(&ftrace_pids) && (!*pos))
+       if (!ftrace_pids_enabled() && (!*pos))
                return (void *) 1;
 
        return seq_list_start(&ftrace_pids, *pos);
@@ -5610,6 +5625,7 @@ static struct ftrace_ops graph_ops = {
        .func                   = ftrace_stub,
        .flags                  = FTRACE_OPS_FL_RECURSION_SAFE |
                                   FTRACE_OPS_FL_INITIALIZED |
+                                  FTRACE_OPS_FL_PID |
                                   FTRACE_OPS_FL_STUB,
 #ifdef FTRACE_GRAPH_TRAMP_ADDR
        .trampoline             = FTRACE_GRAPH_TRAMP_ADDR,
index df30632f0bef9ec1c36a48d83a6eb87cd18ee405..ff19f66d3f7fbd635a44cc03614b5fbe4485cc56 100644 (file)
@@ -119,7 +119,7 @@ unsigned long iommu_tbl_range_alloc(struct device *dev,
        unsigned long align_mask = 0;
 
        if (align_order > 0)
-               align_mask = 0xffffffffffffffffl >> (64 - align_order);
+               align_mask = ~0ul >> (BITS_PER_LONG - align_order);
 
        /* Sanity check */
        if (unlikely(npages == 0)) {
index 1132d733556dbc330d32eda5460f55e6e067b627..17c75a4246c8bbab8b56fe4d562cd85ea670a21f 100644 (file)
--- a/mm/cma.h
+++ b/mm/cma.h
@@ -16,7 +16,7 @@ struct cma {
 extern struct cma cma_areas[MAX_CMA_AREAS];
 extern unsigned cma_area_count;
 
-static unsigned long cma_bitmap_maxno(struct cma *cma)
+static inline unsigned long cma_bitmap_maxno(struct cma *cma)
 {
        return cma->count >> cma->order_per_bit;
 }
index c107094f79bae9ee895bd6bf30976d900f16c141..097c7a4bfbd9f13f4845acae80d73aa7b0e66fb2 100644 (file)
@@ -1676,12 +1676,7 @@ static void __split_huge_page_refcount(struct page *page,
                /* after clearing PageTail the gup refcount can be released */
                smp_mb__after_atomic();
 
-               /*
-                * retain hwpoison flag of the poisoned tail page:
-                *   fix for the unsuitable process killed on Guest Machine(KVM)
-                *   by the memory-failure.
-                */
-               page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP | __PG_HWPOISON;
+               page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
                page_tail->flags |= (page->flags &
                                     ((1L << PG_referenced) |
                                      (1L << PG_swapbacked) |
index 6c513a63ea84c3c7ffd41201b7a419ff7b6dfd5d..7b28e9cdf1c7686428fe49802fced44088043555 100644 (file)
@@ -2,7 +2,7 @@
  * This file contains shadow memory manipulation code.
  *
  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
+ * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
  *
  * Some of code borrowed from https://github.com/xairy/linux by
  *        Andrey Konovalov <adech.fo@gmail.com>
index 680ceedf810ab4c9cd08c9929f5d445de9f5aa6a..e07c94fbd0ac5a141ecf95ab7d39d046fea13e67 100644 (file)
@@ -2,7 +2,7 @@
  * This file contains error reporting code.
  *
  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
+ * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
  *
  * Some of code borrowed from https://github.com/xairy/linux by
  *        Andrey Konovalov <adech.fo@gmail.com>
index c53543d892828e75796239d6ce36afa90203085b..1f4446a90cef07c67ee1082b83f0ca87ebfefea1 100644 (file)
@@ -909,6 +909,18 @@ int get_hwpoison_page(struct page *page)
         * directly for tail pages.
         */
        if (PageTransHuge(head)) {
+               /*
+                * Non anonymous thp exists only in allocation/free time. We
+                * can't handle such a case correctly, so let's give it up.
+                * This should be better than triggering BUG_ON when kernel
+                * tries to touch the "partially handled" page.
+                */
+               if (!PageAnon(head)) {
+                       pr_err("MCE: %#lx: non anonymous thp\n",
+                               page_to_pfn(page));
+                       return 0;
+               }
+
                if (get_page_unless_zero(head)) {
                        if (PageTail(page))
                                get_page(page);
@@ -1134,17 +1146,11 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        }
 
        if (!PageHuge(p) && PageTransHuge(hpage)) {
-               if (!PageAnon(hpage)) {
-                       pr_err("MCE: %#lx: non anonymous thp\n", pfn);
-                       if (TestClearPageHWPoison(p))
-                               atomic_long_sub(nr_pages, &num_poisoned_pages);
-                       put_page(p);
-                       if (p != hpage)
-                               put_page(hpage);
-                       return -EBUSY;
-               }
-               if (unlikely(split_huge_page(hpage))) {
-                       pr_err("MCE: %#lx: thp split failed\n", pfn);
+               if (!PageAnon(hpage) || unlikely(split_huge_page(hpage))) {
+                       if (!PageAnon(hpage))
+                               pr_err("MCE: %#lx: non anonymous thp\n", pfn);
+                       else
+                               pr_err("MCE: %#lx: thp split failed\n", pfn);
                        if (TestClearPageHWPoison(p))
                                atomic_long_sub(nr_pages, &num_poisoned_pages);
                        put_page(p);
@@ -1209,9 +1215,9 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        if (!PageHWPoison(p)) {
                printk(KERN_ERR "MCE %#lx: just unpoisoned\n", pfn);
                atomic_long_sub(nr_pages, &num_poisoned_pages);
+               unlock_page(hpage);
                put_page(hpage);
-               res = 0;
-               goto out;
+               return 0;
        }
        if (hwpoison_filter(p)) {
                if (TestClearPageHWPoison(p))
@@ -1535,6 +1541,8 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags)
                 */
                ret = __get_any_page(page, pfn, 0);
                if (!PageLRU(page)) {
+                       /* Drop page reference which is from __get_any_page() */
+                       put_page(page);
                        pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n",
                                pfn, page->flags);
                        return -EIO;
@@ -1564,13 +1572,12 @@ static int soft_offline_huge_page(struct page *page, int flags)
        unlock_page(hpage);
 
        ret = isolate_huge_page(hpage, &pagelist);
-       if (ret) {
-               /*
-                * get_any_page() and isolate_huge_page() takes a refcount each,
-                * so need to drop one here.
-                */
-               put_page(hpage);
-       } else {
+       /*
+        * get_any_page() and isolate_huge_page() takes a refcount each,
+        * so need to drop one here.
+        */
+       put_page(hpage);
+       if (!ret) {
                pr_info("soft offline: %#lx hugepage failed to isolate\n", pfn);
                return -EBUSY;
        }
@@ -1656,6 +1663,8 @@ static int __soft_offline_page(struct page *page, int flags)
                inc_zone_page_state(page, NR_ISOLATED_ANON +
                                        page_is_file_cache(page));
                list_add(&page->lru, &pagelist);
+               if (!TestSetPageHWPoison(page))
+                       atomic_long_inc(&num_poisoned_pages);
                ret = migrate_pages(&pagelist, new_page, NULL, MPOL_MF_MOVE_ALL,
                                        MIGRATE_SYNC, MR_MEMORY_FAILURE);
                if (ret) {
@@ -1670,9 +1679,8 @@ static int __soft_offline_page(struct page *page, int flags)
                                pfn, ret, page->flags);
                        if (ret > 0)
                                ret = -EIO;
-               } else {
-                       SetPageHWPoison(page);
-                       atomic_long_inc(&num_poisoned_pages);
+                       if (TestClearPageHWPoison(page))
+                               atomic_long_dec(&num_poisoned_pages);
                }
        } else {
                pr_info("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n",
index 26fbba7d888f887c3383c1bb5829cb4f204e2040..6da82bcb0a8b66b7326c1a021a7eac3b476cd85e 100644 (file)
@@ -446,7 +446,7 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn)
        int nr_pages = PAGES_PER_SECTION;
        int nid = pgdat->node_id;
        int zone_type;
-       unsigned long flags;
+       unsigned long flags, pfn;
        int ret;
 
        zone_type = zone - pgdat->node_zones;
@@ -461,6 +461,14 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn)
        pgdat_resize_unlock(zone->zone_pgdat, &flags);
        memmap_init_zone(nr_pages, nid, zone_type,
                         phys_start_pfn, MEMMAP_HOTPLUG);
+
+       /* online_page_range is called later and expects pages reserved */
+       for (pfn = phys_start_pfn; pfn < phys_start_pfn + nr_pages; pfn++) {
+               if (!pfn_valid(pfn))
+                       continue;
+
+               SetPageReserved(pfn_to_page(pfn));
+       }
        return 0;
 }
 
@@ -1269,6 +1277,7 @@ int __ref add_memory(int nid, u64 start, u64 size)
 
        /* create new memmap entry */
        firmware_map_add_hotplug(start, start + size, "System RAM");
+       memblock_add_node(start, size, nid);
 
        goto out;
 
@@ -2005,6 +2014,8 @@ void __ref remove_memory(int nid, u64 start, u64 size)
 
        /* remove memmap entry */
        firmware_map_remove(start, start + size, "System RAM");
+       memblock_free(start, size);
+       memblock_remove(start, size);
 
        arch_remove_memory(start, size);
 
index ee401e4e5ef187c92247d03dd6d2ea0893092d1c..eb4267107d1fee9fa2a55e4076c014500e3b1edb 100644 (file)
@@ -880,7 +880,8 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
        /* Establish migration ptes or remove ptes */
        if (page_mapped(page)) {
                try_to_unmap(page,
-                       TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+                       TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS|
+                       TTU_IGNORE_HWPOISON);
                page_was_mapped = 1;
        }
 
@@ -950,7 +951,10 @@ out:
                list_del(&page->lru);
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
-               if (reason != MR_MEMORY_FAILURE)
+               /* Soft-offlined page shouldn't go through lru cache list */
+               if (reason == MR_MEMORY_FAILURE)
+                       put_page(page);
+               else
                        putback_lru_page(page);
        }
 
index 22cddd3e5de8433952e99438d3260ae9ff20bd8d..5cccc127ef81f1d64ca46f9ce9ad50f519d4ea9f 100644 (file)
@@ -2063,10 +2063,10 @@ static struct notifier_block ratelimit_nb = {
  */
 void __init page_writeback_init(void)
 {
+       BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL));
+
        writeback_set_ratelimit();
        register_cpu_notifier(&ratelimit_nb);
-
-       BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL));
 }
 
 /**
index ef19f22b2b7de1728fb4ed8d6451d29bb993a928..df959b7d608518edf9ab5c577e6b19afa8d88ed9 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/interrupt.h>
-#include <linux/rwsem.h>
 #include <linux/pagemap.h>
 #include <linux/jiffies.h>
 #include <linux/bootmem.h>
@@ -981,21 +980,21 @@ static void __init __free_pages_boot_core(struct page *page,
 
 #if defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) || \
        defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP)
-/* Only safe to use early in boot when initialisation is single-threaded */
+
 static struct mminit_pfnnid_cache early_pfnnid_cache __meminitdata;
 
 int __meminit early_pfn_to_nid(unsigned long pfn)
 {
+       static DEFINE_SPINLOCK(early_pfn_lock);
        int nid;
 
-       /* The system will behave unpredictably otherwise */
-       BUG_ON(system_state != SYSTEM_BOOTING);
-
+       spin_lock(&early_pfn_lock);
        nid = __early_pfn_to_nid(pfn, &early_pfnnid_cache);
-       if (nid >= 0)
-               return nid;
-       /* just returns 0 */
-       return 0;
+       if (nid < 0)
+               nid = 0;
+       spin_unlock(&early_pfn_lock);
+
+       return nid;
 }
 #endif
 
@@ -1060,7 +1059,15 @@ static void __init deferred_free_range(struct page *page,
                __free_pages_boot_core(page, pfn, 0);
 }
 
-static __initdata DECLARE_RWSEM(pgdat_init_rwsem);
+/* Completion tracking for deferred_init_memmap() threads */
+static atomic_t pgdat_init_n_undone __initdata;
+static __initdata DECLARE_COMPLETION(pgdat_init_all_done_comp);
+
+static inline void __init pgdat_init_report_one_done(void)
+{
+       if (atomic_dec_and_test(&pgdat_init_n_undone))
+               complete(&pgdat_init_all_done_comp);
+}
 
 /* Initialise remaining memory on a node */
 static int __init deferred_init_memmap(void *data)
@@ -1077,7 +1084,7 @@ static int __init deferred_init_memmap(void *data)
        const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id);
 
        if (first_init_pfn == ULONG_MAX) {
-               up_read(&pgdat_init_rwsem);
+               pgdat_init_report_one_done();
                return 0;
        }
 
@@ -1177,7 +1184,8 @@ free_range:
 
        pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages,
                                        jiffies_to_msecs(jiffies - start));
-       up_read(&pgdat_init_rwsem);
+
+       pgdat_init_report_one_done();
        return 0;
 }
 
@@ -1185,14 +1193,17 @@ void __init page_alloc_init_late(void)
 {
        int nid;
 
+       /* There will be num_node_state(N_MEMORY) threads */
+       atomic_set(&pgdat_init_n_undone, num_node_state(N_MEMORY));
        for_each_node_state(nid, N_MEMORY) {
-               down_read(&pgdat_init_rwsem);
                kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid);
        }
 
        /* Block until all are initialised */
-       down_write(&pgdat_init_rwsem);
-       up_write(&pgdat_init_rwsem);
+       wait_for_completion(&pgdat_init_all_done_comp);
+
+       /* Reinit limits that are based on free pages after the kernel is up */
+       files_maxfiles_init();
 }
 #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
 
@@ -1285,6 +1296,10 @@ static inline int check_new_page(struct page *page)
                bad_reason = "non-NULL mapping";
        if (unlikely(atomic_read(&page->_count) != 0))
                bad_reason = "nonzero _count";
+       if (unlikely(page->flags & __PG_HWPOISON)) {
+               bad_reason = "HWPoisoned (hardware-corrupted)";
+               bad_flags = __PG_HWPOISON;
+       }
        if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_PREP)) {
                bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set";
                bad_flags = PAGE_FLAGS_CHECK_AT_PREP;
@@ -5045,6 +5060,10 @@ static unsigned long __meminit zone_spanned_pages_in_node(int nid,
 {
        unsigned long zone_start_pfn, zone_end_pfn;
 
+       /* When hotadd a new node, the node should be empty */
+       if (!node_start_pfn && !node_end_pfn)
+               return 0;
+
        /* Get the start and end of the zone */
        zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
        zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
@@ -5108,6 +5127,10 @@ static unsigned long __meminit zone_absent_pages_in_node(int nid,
        unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type];
        unsigned long zone_start_pfn, zone_end_pfn;
 
+       /* When hotadd a new node, the node should be empty */
+       if (!node_start_pfn && !node_end_pfn)
+               return 0;
+
        zone_start_pfn = clamp(node_start_pfn, zone_low, zone_high);
        zone_end_pfn = clamp(node_end_pfn, zone_low, zone_high);
 
index 4caf8ed24d6586e32ab910f28f945c01cef6373b..dbe0c1e8349c72ac569a58289da702a841104951 100644 (file)
@@ -3363,8 +3363,8 @@ put_path:
  * shmem_kernel_file_setup - get an unlinked file living in tmpfs which must be
  *     kernel internal.  There will be NO LSM permission checks against the
  *     underlying inode.  So users of this interface must do LSM checks at a
- *     higher layer.  The one user is the big_key implementation.  LSM checks
- *     are provided at the key level rather than the inode level.
+ *     higher layer.  The users are the big_key and shm implementations.  LSM
+ *     checks are provided at the key or shm level rather than the inode.
  * @name: name for dentry (to be seen in /proc/<pid>/maps
  * @size: size to be set for the file
  * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
index 3e5f8f29c28640e44af5f5f9d1c3553986064588..86831105a09f44ffae37c074a6e5587c5b7056ce 100644 (file)
@@ -37,8 +37,7 @@ struct kmem_cache *kmem_cache;
                SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE | \
                SLAB_FAILSLAB)
 
-#define SLAB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \
-               SLAB_CACHE_DMA | SLAB_NOTRACK)
+#define SLAB_MERGE_SAME (SLAB_RECLAIM_ACCOUNT | SLAB_CACHE_DMA | SLAB_NOTRACK)
 
 /*
  * Merge control. If this is set then no merging of slab caches will occur.
index e61445dce04e3cc83e9704e84f3d5bf9074b31db..8286938c70ded6b82d4268174c92669a90eeb674 100644 (file)
@@ -973,22 +973,18 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                 *    caller can stall after page list has been processed.
                 *
                 * 2) Global or new memcg reclaim encounters a page that is
-                *    not marked for immediate reclaim or the caller does not
-                *    have __GFP_IO. In this case mark the page for immediate
+                *    not marked for immediate reclaim, or the caller does not
+                *    have __GFP_FS (or __GFP_IO if it's simply going to swap,
+                *    not to fs). In this case mark the page for immediate
                 *    reclaim and continue scanning.
                 *
-                *    __GFP_IO is checked  because a loop driver thread might
+                *    Require may_enter_fs because we would wait on fs, which
+                *    may not have submitted IO yet. And the loop driver might
                 *    enter reclaim, and deadlock if it waits on a page for
                 *    which it is needed to do the write (loop masks off
                 *    __GFP_IO|__GFP_FS for this reason); but more thought
                 *    would probably show more reasons.
                 *
-                *    Don't require __GFP_FS, since we're not going into the
-                *    FS, just waiting on its writeback completion. Worryingly,
-                *    ext4 gfs2 and xfs allocate pages with
-                *    grab_cache_page_write_begin(,,AOP_FLAG_NOFS), so testing
-                *    may_enter_fs here is liable to OOM on them.
-                *
                 * 3) Legacy memcg encounters a page that is not already marked
                 *    PageReclaim. memcg does not have any dirty pages
                 *    throttling so we could easily OOM just because too many
@@ -1005,7 +1001,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
 
                        /* Case 2 above */
                        } else if (sane_reclaim(sc) ||
-                           !PageReclaim(page) || !(sc->gfp_mask & __GFP_IO)) {
+                           !PageReclaim(page) || !may_enter_fs) {
                                /*
                                 * This is slightly racy - end_page_writeback()
                                 * might have just cleared PageReclaim, then
index 9dd49ca67dbc22a905999de21b8355475ba40052..6e70ddb158b4bc121a0f32e7a53fecf8125e8354 100644 (file)
@@ -704,6 +704,7 @@ static void p9_virtio_remove(struct virtio_device *vdev)
 
        mutex_unlock(&virtio_9p_lock);
 
+       vdev->config->reset(vdev);
        vdev->config->del_vqs(vdev);
 
        sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
index 1997538a5d23d93ddca9724fd3787dc0b0b2595a..3b78e8473a01b4a82e376266b04078e714ce1e26 100644 (file)
@@ -264,6 +264,7 @@ void ax25_disconnect(ax25_cb *ax25, int reason)
 {
        ax25_clear_queues(ax25);
 
+       ax25_stop_heartbeat(ax25);
        ax25_stop_t1timer(ax25);
        ax25_stop_t2timer(ax25);
        ax25_stop_t3timer(ax25);
index fb54e6aed096edd267fc211e4cd2a0139fe71f8a..6d0b471eede8639f55b33c5c4d434c8fddef6ee5 100644 (file)
@@ -1138,6 +1138,9 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: packet to check
  * @hdr_size: size of the encapsulation header
+ *
+ * Returns true if the packet was snooped and consumed by DAT. False if the
+ * packet has to be delivered to the interface
  */
 bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
                                         struct sk_buff *skb, int hdr_size)
@@ -1145,7 +1148,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
        uint16_t type;
        __be32 ip_src, ip_dst;
        uint8_t *hw_src, *hw_dst;
-       bool ret = false;
+       bool dropped = false;
        unsigned short vid;
 
        if (!atomic_read(&bat_priv->distributed_arp_table))
@@ -1174,12 +1177,17 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
        /* if this REPLY is directed to a client of mine, let's deliver the
         * packet to the interface
         */
-       ret = !batadv_is_my_client(bat_priv, hw_dst, vid);
+       dropped = !batadv_is_my_client(bat_priv, hw_dst, vid);
+
+       /* if this REPLY is sent on behalf of a client of mine, let's drop the
+        * packet because the client will reply by itself
+        */
+       dropped |= batadv_is_my_client(bat_priv, hw_src, vid);
 out:
-       if (ret)
+       if (dropped)
                kfree_skb(skb);
-       /* if ret == false -> packet has to be delivered to the interface */
-       return ret;
+       /* if dropped == false -> deliver to the interface */
+       return dropped;
 }
 
 /**
index bb01586206289929f8c5e43153b75f9c279b9f85..cffa92dd98778bf2ffdf11107243fcc0f60cab6b 100644 (file)
@@ -439,6 +439,8 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
 
        INIT_HLIST_NODE(&gw_node->list);
        gw_node->orig_node = orig_node;
+       gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
+       gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
        atomic_set(&gw_node->refcount, 1);
 
        spin_lock_bh(&bat_priv->gw.list_lock);
index c002961da75d655deb813990f5706cf37fbd6d7d..a2fc843c22432e790980fa15653cf95e6c60b384 100644 (file)
@@ -479,6 +479,9 @@ out:
  */
 void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan)
 {
+       if (!vlan)
+               return;
+
        if (atomic_dec_and_test(&vlan->refcount)) {
                spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock);
                hlist_del_rcu(&vlan->list);
index b4824951010ba6b42bf7d7c7eb62c529ed340158..5e953297d3b2bda513cd9ad90e7e634928f34a20 100644 (file)
@@ -594,6 +594,9 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 
        /* increase the refcounter of the related vlan */
        vlan = batadv_softif_vlan_get(bat_priv, vid);
+       if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d",
+                addr, BATADV_PRINT_VID(vid)))
+               goto out;
 
        batadv_dbg(BATADV_DBG_TT, bat_priv,
                   "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
@@ -1034,6 +1037,7 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
        struct batadv_tt_local_entry *tt_local_entry;
        uint16_t flags, curr_flags = BATADV_NO_FLAGS;
        struct batadv_softif_vlan *vlan;
+       void *tt_entry_exists;
 
        tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
        if (!tt_local_entry)
@@ -1061,11 +1065,22 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
         * immediately purge it
         */
        batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
-       hlist_del_rcu(&tt_local_entry->common.hash_entry);
+
+       tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash,
+                                            batadv_compare_tt,
+                                            batadv_choose_tt,
+                                            &tt_local_entry->common);
+       if (!tt_entry_exists)
+               goto out;
+
+       /* extra call to free the local tt entry */
        batadv_tt_local_entry_free_ref(tt_local_entry);
 
        /* decrease the reference held for this vlan */
        vlan = batadv_softif_vlan_get(bat_priv, vid);
+       if (!vlan)
+               goto out;
+
        batadv_softif_vlan_free_ref(vlan);
        batadv_softif_vlan_free_ref(vlan);
 
@@ -1166,8 +1181,10 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
                        /* decrease the reference held for this vlan */
                        vlan = batadv_softif_vlan_get(bat_priv,
                                                      tt_common_entry->vid);
-                       batadv_softif_vlan_free_ref(vlan);
-                       batadv_softif_vlan_free_ref(vlan);
+                       if (vlan) {
+                               batadv_softif_vlan_free_ref(vlan);
+                               batadv_softif_vlan_free_ref(vlan);
+                       }
 
                        batadv_tt_local_entry_free_ref(tt_local);
                }
@@ -3207,8 +3224,10 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
 
                        /* decrease the reference held for this vlan */
                        vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid);
-                       batadv_softif_vlan_free_ref(vlan);
-                       batadv_softif_vlan_free_ref(vlan);
+                       if (vlan) {
+                               batadv_softif_vlan_free_ref(vlan);
+                               batadv_softif_vlan_free_ref(vlan);
+                       }
 
                        batadv_tt_local_entry_free_ref(tt_local);
                }
index 7998fb27916568da087b2734a017355158044a75..92720f3fe57370137f22ae3d2b76b390da09e9a1 100644 (file)
@@ -7820,7 +7820,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
        /* Make sure we copy only the significant bytes based on the
         * encryption key size, and set the rest of the value to zeroes.
         */
-       memcpy(ev.key.val, key->val, sizeof(key->enc_size));
+       memcpy(ev.key.val, key->val, key->enc_size);
        memset(ev.key.val + key->enc_size, 0,
               sizeof(ev.key.val) - key->enc_size);
 
index 3d0f7d2a06162248a1e6589fe3d59022f9dded0d..ad82324f710f0f97427a51c632e5a8aebfaba292 100644 (file)
@@ -2312,6 +2312,10 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
                return 1;
 
        chan = conn->smp;
+       if (!chan) {
+               BT_ERR("SMP security requested but not available");
+               return 1;
+       }
 
        if (!hci_dev_test_flag(hcon->hdev, HCI_LE_ENABLED))
                return 1;
index 0ff6e1bbca910a35fc94794d39ac8978085b144d..fa7bfced888ec0f3b7d8a5ceff17b597cbe9b79e 100644 (file)
@@ -37,15 +37,30 @@ static inline int should_deliver(const struct net_bridge_port *p,
 
 int br_dev_queue_push_xmit(struct sock *sk, struct sk_buff *skb)
 {
-       if (!is_skb_forwardable(skb->dev, skb)) {
-               kfree_skb(skb);
-       } else {
-               skb_push(skb, ETH_HLEN);
-               br_drop_fake_rtable(skb);
-               skb_sender_cpu_clear(skb);
-               dev_queue_xmit(skb);
+       if (!is_skb_forwardable(skb->dev, skb))
+               goto drop;
+
+       skb_push(skb, ETH_HLEN);
+       br_drop_fake_rtable(skb);
+       skb_sender_cpu_clear(skb);
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL &&
+           (skb->protocol == htons(ETH_P_8021Q) ||
+            skb->protocol == htons(ETH_P_8021AD))) {
+               int depth;
+
+               if (!__vlan_get_protocol(skb, skb->protocol, &depth))
+                       goto drop;
+
+               skb_set_network_header(skb, depth);
        }
 
+       dev_queue_xmit(skb);
+
+       return 0;
+
+drop:
+       kfree_skb(skb);
        return 0;
 }
 EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);
index c11cf2611db0c870542969b6847d0a61d18b64d4..c94321955db711fdc964930c51a69d1290d39490 100644 (file)
@@ -351,7 +351,6 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
        if (state == MDB_TEMPORARY)
                mod_timer(&p->timer, now + br->multicast_membership_interval);
 
-       br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
        return 0;
 }
 
@@ -446,6 +445,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
                if (p->port->state == BR_STATE_DISABLED)
                        goto unlock;
 
+               entry->state = p->state;
                rcu_assign_pointer(*pp, p->next);
                hlist_del_init(&p->mglist);
                del_timer(&p->timer);
index 742a6c27d7a222bc3c53c288b4a6915194310fe6..0b39dcc65b94f0aa571dc22dc0c97afbf4e3d744 100644 (file)
@@ -39,6 +39,16 @@ static void br_multicast_start_querier(struct net_bridge *br,
                                       struct bridge_mcast_own_query *query);
 static void br_multicast_add_router(struct net_bridge *br,
                                    struct net_bridge_port *port);
+static void br_ip4_multicast_leave_group(struct net_bridge *br,
+                                        struct net_bridge_port *port,
+                                        __be32 group,
+                                        __u16 vid);
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_leave_group(struct net_bridge *br,
+                                        struct net_bridge_port *port,
+                                        const struct in6_addr *group,
+                                        __u16 vid);
+#endif
 unsigned int br_mdb_rehash_seq;
 
 static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
@@ -1010,9 +1020,15 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
                        continue;
                }
 
-               err = br_ip4_multicast_add_group(br, port, group, vid);
-               if (err)
-                       break;
+               if ((type == IGMPV3_CHANGE_TO_INCLUDE ||
+                    type == IGMPV3_MODE_IS_INCLUDE) &&
+                   ntohs(grec->grec_nsrcs) == 0) {
+                       br_ip4_multicast_leave_group(br, port, group, vid);
+               } else {
+                       err = br_ip4_multicast_add_group(br, port, group, vid);
+                       if (err)
+                               break;
+               }
        }
 
        return err;
@@ -1071,10 +1087,17 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
                        continue;
                }
 
-               err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
-                                                vid);
-               if (err)
-                       break;
+               if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE ||
+                    grec->grec_type == MLD2_MODE_IS_INCLUDE) &&
+                   ntohs(*nsrcs) == 0) {
+                       br_ip6_multicast_leave_group(br, port, &grec->grec_mca,
+                                                    vid);
+               } else {
+                       err = br_ip6_multicast_add_group(br, port,
+                                                        &grec->grec_mca, vid);
+                       if (!err)
+                               break;
+               }
        }
 
        return err;
@@ -1393,8 +1416,7 @@ br_multicast_leave_group(struct net_bridge *br,
 
        spin_lock(&br->multicast_lock);
        if (!netif_running(br->dev) ||
-           (port && port->state == BR_STATE_DISABLED) ||
-           timer_pending(&other_query->timer))
+           (port && port->state == BR_STATE_DISABLED))
                goto out;
 
        mdb = mlock_dereference(br->mdb, br);
@@ -1402,6 +1424,31 @@ br_multicast_leave_group(struct net_bridge *br,
        if (!mp)
                goto out;
 
+       if (port && (port->flags & BR_MULTICAST_FAST_LEAVE)) {
+               struct net_bridge_port_group __rcu **pp;
+
+               for (pp = &mp->ports;
+                    (p = mlock_dereference(*pp, br)) != NULL;
+                    pp = &p->next) {
+                       if (p->port != port)
+                               continue;
+
+                       rcu_assign_pointer(*pp, p->next);
+                       hlist_del_init(&p->mglist);
+                       del_timer(&p->timer);
+                       call_rcu_bh(&p->rcu, br_multicast_free_pg);
+                       br_mdb_notify(br->dev, port, group, RTM_DELMDB);
+
+                       if (!mp->ports && !mp->mglist &&
+                           netif_running(br->dev))
+                               mod_timer(&mp->timer, jiffies);
+               }
+               goto out;
+       }
+
+       if (timer_pending(&other_query->timer))
+               goto out;
+
        if (br->multicast_querier) {
                __br_multicast_send_query(br, port, &mp->addr);
 
@@ -1427,28 +1474,6 @@ br_multicast_leave_group(struct net_bridge *br,
                }
        }
 
-       if (port && (port->flags & BR_MULTICAST_FAST_LEAVE)) {
-               struct net_bridge_port_group __rcu **pp;
-
-               for (pp = &mp->ports;
-                    (p = mlock_dereference(*pp, br)) != NULL;
-                    pp = &p->next) {
-                       if (p->port != port)
-                               continue;
-
-                       rcu_assign_pointer(*pp, p->next);
-                       hlist_del_init(&p->mglist);
-                       del_timer(&p->timer);
-                       call_rcu_bh(&p->rcu, br_multicast_free_pg);
-                       br_mdb_notify(br->dev, port, group, RTM_DELMDB);
-
-                       if (!mp->ports && !mp->mglist &&
-                           netif_running(br->dev))
-                               mod_timer(&mp->timer, jiffies);
-               }
-               goto out;
-       }
-
        now = jiffies;
        time = now + br->multicast_last_member_count *
                     br->multicast_last_member_interval;
index 364bdc98bd9bef003dfe4f17a1f2ac3048c0bd02..4d74a0639c4ccd040b6371665e6a74f8dca6f800 100644 (file)
@@ -112,6 +112,8 @@ static inline size_t br_port_info_size(void)
                + nla_total_size(1)     /* IFLA_BRPORT_FAST_LEAVE */
                + nla_total_size(1)     /* IFLA_BRPORT_LEARNING */
                + nla_total_size(1)     /* IFLA_BRPORT_UNICAST_FLOOD */
+               + nla_total_size(1)     /* IFLA_BRPORT_PROXYARP */
+               + nla_total_size(1)     /* IFLA_BRPORT_PROXYARP_WIFI */
                + 0;
 }
 
@@ -506,6 +508,8 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = {
        [IFLA_BRPORT_FAST_LEAVE]= { .type = NLA_U8 },
        [IFLA_BRPORT_LEARNING]  = { .type = NLA_U8 },
        [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
+       [IFLA_BRPORT_PROXYARP]  = { .type = NLA_U8 },
+       [IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 },
 };
 
 /* Change the state of the port and notify spanning tree */
@@ -693,9 +697,17 @@ static int br_port_slave_changelink(struct net_device *brdev,
                                    struct nlattr *tb[],
                                    struct nlattr *data[])
 {
+       struct net_bridge *br = netdev_priv(brdev);
+       int ret;
+
        if (!data)
                return 0;
-       return br_setport(br_port_get_rtnl(dev), data);
+
+       spin_lock_bh(&br->lock);
+       ret = br_setport(br_port_get_rtnl(dev), data);
+       spin_unlock_bh(&br->lock);
+
+       return ret;
 }
 
 static int br_port_fill_slave_info(struct sk_buff *skb,
index b4b6dab9c2859730d3ba9b5bc17f8302ddca6510..ed74ffaa851ff43d08c3edb4a158ab21af27e1a3 100644 (file)
@@ -209,8 +209,9 @@ void br_transmit_config(struct net_bridge_port *p)
                br_send_config_bpdu(p, &bpdu);
                p->topology_change_ack = 0;
                p->config_pending = 0;
-               mod_timer(&p->hold_timer,
-                         round_jiffies(jiffies + BR_HOLD_TIME));
+               if (p->br->stp_enabled == BR_KERNEL_STP)
+                       mod_timer(&p->hold_timer,
+                                 round_jiffies(jiffies + BR_HOLD_TIME));
        }
 }
 
index a2730e7196cd7080b96a441f5cc40591320862e5..4ca449a161320f7ef1c6f4864940e8557a7d18e3 100644 (file)
@@ -48,7 +48,8 @@ void br_stp_enable_bridge(struct net_bridge *br)
        struct net_bridge_port *p;
 
        spin_lock_bh(&br->lock);
-       mod_timer(&br->hello_timer, jiffies + br->hello_time);
+       if (br->stp_enabled == BR_KERNEL_STP)
+               mod_timer(&br->hello_timer, jiffies + br->hello_time);
        mod_timer(&br->gc_timer, jiffies + HZ/10);
 
        br_config_bpdu_generation(br);
@@ -127,6 +128,7 @@ static void br_stp_start(struct net_bridge *br)
        int r;
        char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL };
        char *envp[] = { NULL };
+       struct net_bridge_port *p;
 
        r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
 
@@ -140,6 +142,10 @@ static void br_stp_start(struct net_bridge *br)
        if (r == 0) {
                br->stp_enabled = BR_USER_STP;
                br_debug(br, "userspace STP started\n");
+               /* Stop hello and hold timers */
+               del_timer(&br->hello_timer);
+               list_for_each_entry(p, &br->port_list, list)
+                       del_timer(&p->hold_timer);
        } else {
                br->stp_enabled = BR_KERNEL_STP;
                br_debug(br, "using kernel STP\n");
@@ -156,12 +162,17 @@ static void br_stp_stop(struct net_bridge *br)
        int r;
        char *argv[] = { BR_STP_PROG, br->dev->name, "stop", NULL };
        char *envp[] = { NULL };
+       struct net_bridge_port *p;
 
        if (br->stp_enabled == BR_USER_STP) {
                r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
                br_info(br, "userspace STP stopped, return code %d\n", r);
 
                /* To start timers on any ports left in blocking */
+               mod_timer(&br->hello_timer, jiffies + br->hello_time);
+               list_for_each_entry(p, &br->port_list, list)
+                       mod_timer(&p->hold_timer,
+                                 round_jiffies(jiffies + BR_HOLD_TIME));
                spin_lock_bh(&br->lock);
                br_port_state_selection(br);
                spin_unlock_bh(&br->lock);
index 7caf7fae2d5b8aa369b924e1c87a47c343fb8954..5f0f5af0ec35bf8c216935713a9d5f803456e1ab 100644 (file)
@@ -40,7 +40,9 @@ static void br_hello_timer_expired(unsigned long arg)
        if (br->dev->flags & IFF_UP) {
                br_config_bpdu_generation(br);
 
-               mod_timer(&br->hello_timer, round_jiffies(jiffies + br->hello_time));
+               if (br->stp_enabled != BR_USER_STP)
+                       mod_timer(&br->hello_timer,
+                                 round_jiffies(jiffies + br->hello_time));
        }
        spin_unlock(&br->lock);
 }
index 3cc71b9f551756ca63b1299e95d9b6424e5afb72..cc858919108ee1f9645bce1046be8650a640d821 100644 (file)
@@ -121,12 +121,13 @@ static void caif_flow_ctrl(struct sock *sk, int mode)
  * Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are
  * not dropped, but CAIF is sending flow off instead.
  */
-static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+static void caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        int err;
        unsigned long flags;
        struct sk_buff_head *list = &sk->sk_receive_queue;
        struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+       bool queued = false;
 
        if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
                (unsigned int)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
@@ -139,7 +140,8 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
        err = sk_filter(sk, skb);
        if (err)
-               return err;
+               goto out;
+
        if (!sk_rmem_schedule(sk, skb, skb->truesize) && rx_flow_is_on(cf_sk)) {
                set_rx_flow_off(cf_sk);
                net_dbg_ratelimited("sending flow OFF due to rmem_schedule\n");
@@ -147,21 +149,16 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        }
        skb->dev = NULL;
        skb_set_owner_r(skb, sk);
-       /* Cache the SKB length before we tack it onto the receive
-        * queue. Once it is added it no longer belongs to us and
-        * may be freed by other threads of control pulling packets
-        * from the queue.
-        */
        spin_lock_irqsave(&list->lock, flags);
-       if (!sock_flag(sk, SOCK_DEAD))
+       queued = !sock_flag(sk, SOCK_DEAD);
+       if (queued)
                __skb_queue_tail(list, skb);
        spin_unlock_irqrestore(&list->lock, flags);
-
-       if (!sock_flag(sk, SOCK_DEAD))
+out:
+       if (queued)
                sk->sk_data_ready(sk);
        else
                kfree_skb(skb);
-       return 0;
 }
 
 /* Packet Receive Callback function called from CAIF Stack */
index b80fb91bb3f7e8dc630663cb5e012dc97ac6924f..617088aee21d41ba98d4ef5ebee5d6c002efe029 100644 (file)
@@ -131,6 +131,35 @@ out_noerr:
        goto out;
 }
 
+static struct sk_buff *skb_set_peeked(struct sk_buff *skb)
+{
+       struct sk_buff *nskb;
+
+       if (skb->peeked)
+               return skb;
+
+       /* We have to unshare an skb before modifying it. */
+       if (!skb_shared(skb))
+               goto done;
+
+       nskb = skb_clone(skb, GFP_ATOMIC);
+       if (!nskb)
+               return ERR_PTR(-ENOMEM);
+
+       skb->prev->next = nskb;
+       skb->next->prev = nskb;
+       nskb->prev = skb->prev;
+       nskb->next = skb->next;
+
+       consume_skb(skb);
+       skb = nskb;
+
+done:
+       skb->peeked = 1;
+
+       return skb;
+}
+
 /**
  *     __skb_recv_datagram - Receive a datagram skbuff
  *     @sk: socket
@@ -165,7 +194,9 @@ out_noerr:
 struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
                                    int *peeked, int *off, int *err)
 {
+       struct sk_buff_head *queue = &sk->sk_receive_queue;
        struct sk_buff *skb, *last;
+       unsigned long cpu_flags;
        long timeo;
        /*
         * Caller is allowed not to check sk->sk_err before skb_recv_datagram()
@@ -184,8 +215,6 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
                 * Look at current nfs client by the way...
                 * However, this function was correct in any case. 8)
                 */
-               unsigned long cpu_flags;
-               struct sk_buff_head *queue = &sk->sk_receive_queue;
                int _off = *off;
 
                last = (struct sk_buff *)queue;
@@ -199,7 +228,12 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
                                        _off -= skb->len;
                                        continue;
                                }
-                               skb->peeked = 1;
+
+                               skb = skb_set_peeked(skb);
+                               error = PTR_ERR(skb);
+                               if (IS_ERR(skb))
+                                       goto unlock_err;
+
                                atomic_inc(&skb->users);
                        } else
                                __skb_unlink(skb, queue);
@@ -223,6 +257,8 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
 
        return NULL;
 
+unlock_err:
+       spin_unlock_irqrestore(&queue->lock, cpu_flags);
 no_packet:
        *err = error;
        return NULL;
@@ -622,7 +658,8 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
                    !skb->csum_complete_sw)
                        netdev_rx_csum_fault(skb->dev);
        }
-       skb->csum_valid = !sum;
+       if (!skb_shared(skb))
+               skb->csum_valid = !sum;
        return sum;
 }
 EXPORT_SYMBOL(__skb_checksum_complete_head);
@@ -642,11 +679,13 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb)
                        netdev_rx_csum_fault(skb->dev);
        }
 
-       /* Save full packet checksum */
-       skb->csum = csum;
-       skb->ip_summed = CHECKSUM_COMPLETE;
-       skb->csum_complete_sw = 1;
-       skb->csum_valid = !sum;
+       if (!skb_shared(skb)) {
+               /* Save full packet checksum */
+               skb->csum = csum;
+               skb->ip_summed = CHECKSUM_COMPLETE;
+               skb->csum_complete_sw = 1;
+               skb->csum_valid = !sum;
+       }
 
        return sum;
 }
index e956ce6d13782f2da0a229cabafef663665159eb..002144bea93517d7e2e5b2c0ac00e70c028174a2 100644 (file)
@@ -284,7 +284,9 @@ void dst_release(struct dst_entry *dst)
                int newrefcnt;
 
                newrefcnt = atomic_dec_return(&dst->__refcnt);
-               WARN_ON(newrefcnt < 0);
+               if (unlikely(newrefcnt < 0))
+                       net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
+                                            __func__, dst, newrefcnt);
                if (unlikely(dst->flags & DST_NOCACHE) && !newrefcnt)
                        call_rcu(&dst->rcu_head, dst_destroy_rcu);
        }
index 1f2a126f4ffa07a6e50cd2b57a6042afca3ee3ad..6441f47b1a8ffc78731896fd4ab1b12db43f0992 100644 (file)
@@ -23,7 +23,8 @@ static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state
 
 struct cgroup_cls_state *task_cls_state(struct task_struct *p)
 {
-       return css_cls_state(task_css(p, net_cls_cgrp_id));
+       return css_cls_state(task_css_check(p, net_cls_cgrp_id,
+                                           rcu_read_lock_bh_held()));
 }
 EXPORT_SYMBOL_GPL(task_cls_state);
 
index 1ebdf1c0d1188c309d854bc9145c9b2f5b7b58a4..1cbd209192eacd6b7ec9a13f8180a5138760fc7e 100644 (file)
@@ -3514,8 +3514,6 @@ static int pktgen_thread_worker(void *arg)
 
        set_freezable();
 
-       __set_current_state(TASK_RUNNING);
-
        while (!kthread_should_stop()) {
                pkt_dev = next_to_run(t);
 
@@ -3560,7 +3558,6 @@ static int pktgen_thread_worker(void *arg)
 
                try_to_freeze();
        }
-       set_current_state(TASK_INTERRUPTIBLE);
 
        pr_debug("%s stopping all device\n", t->tsk->comm);
        pktgen_stop(t);
index 87b22c0bc08c2f33fa31948b8b2604f48b8009bc..b42f0e26f89e4cf2e37a8329da549eb5cd1200c5 100644 (file)
@@ -103,10 +103,16 @@ void reqsk_queue_destroy(struct request_sock_queue *queue)
                        spin_lock_bh(&queue->syn_wait_lock);
                        while ((req = lopt->syn_table[i]) != NULL) {
                                lopt->syn_table[i] = req->dl_next;
+                               /* Because of following del_timer_sync(),
+                                * we must release the spinlock here
+                                * or risk a dead lock.
+                                */
+                               spin_unlock_bh(&queue->syn_wait_lock);
                                atomic_inc(&lopt->qlen_dec);
-                               if (del_timer(&req->rsk_timer))
+                               if (del_timer_sync(&req->rsk_timer))
                                        reqsk_put(req);
                                reqsk_put(req);
+                               spin_lock_bh(&queue->syn_wait_lock);
                        }
                        spin_unlock_bh(&queue->syn_wait_lock);
                }
index 9e433d58d2651cf867294a911d0f136e565730ae..dc004b1e1f8515250bb7c7f284b047d2f961f083 100644 (file)
@@ -1804,10 +1804,13 @@ static int do_setlink(const struct sk_buff *skb,
                        goto errout;
 
                nla_for_each_nested(attr, tb[IFLA_VF_PORTS], rem) {
-                       if (nla_type(attr) != IFLA_VF_PORT)
-                               continue;
-                       err = nla_parse_nested(port, IFLA_PORT_MAX,
-                               attr, ifla_port_policy);
+                       if (nla_type(attr) != IFLA_VF_PORT ||
+                           nla_len(attr) < NLA_HDRLEN) {
+                               err = -EINVAL;
+                               goto errout;
+                       }
+                       err = nla_parse_nested(port, IFLA_PORT_MAX, attr,
+                                              ifla_port_policy);
                        if (err < 0)
                                goto errout;
                        if (!port[IFLA_PORT_VF]) {
index 08f16db46070a1520fcdd6892477093e9474af4f..193901d097577a88e7fea3f59450cc041942f8fa 100644 (file)
@@ -1497,7 +1497,8 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
                sock_copy(newsk, sk);
 
                /* SANITY */
-               get_net(sock_net(newsk));
+               if (likely(newsk->sk_net_refcnt))
+                       get_net(sock_net(newsk));
                sk_node_init(&newsk->sk_node);
                sock_lock_init(newsk);
                bh_lock_sock(newsk);
@@ -1967,20 +1968,21 @@ static void __release_sock(struct sock *sk)
  * sk_wait_data - wait for data to arrive at sk_receive_queue
  * @sk:    sock to wait on
  * @timeo: for how long
+ * @skb:   last skb seen on sk_receive_queue
  *
  * Now socket state including sk->sk_err is changed only under lock,
  * hence we may omit checks after joining wait queue.
  * We check receive queue before schedule() only as optimization;
  * it is very likely that release_sock() added new data.
  */
-int sk_wait_data(struct sock *sk, long *timeo)
+int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb)
 {
        int rc;
        DEFINE_WAIT(wait);
 
        prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
-       rc = sk_wait_event(sk, timeo, !skb_queue_empty(&sk->sk_receive_queue));
+       rc = sk_wait_event(sk, timeo, skb_peek_tail(&sk->sk_receive_queue) != skb);
        clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
        finish_wait(sk_sleep(sk), &wait);
        return rc;
index 52a94016526d3c595a71f4affac1a24251f964d7..b5cf13a2800923486ad597c296a66145bc248596 100644 (file)
@@ -886,7 +886,7 @@ verify_sock_status:
                        break;
                }
 
-               sk_wait_data(sk, &timeo);
+               sk_wait_data(sk, &timeo, NULL);
                continue;
        found_ok_skb:
                if (len > skb->len)
index 0917123790eaf09b001c97a733039185fdb0a800..35c47ddd04f0ee3eb965fd99b06bab2ee4670774 100644 (file)
@@ -756,7 +756,8 @@ static int dsa_slave_phy_connect(struct dsa_slave_priv *p,
                return -ENODEV;
 
        /* Use already configured phy mode */
-       p->phy_interface = p->phy->interface;
+       if (p->phy_interface == PHY_INTERFACE_MODE_NA)
+               p->phy_interface = p->phy->interface;
        phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link,
                           p->phy_interface);
 
index f46e4d1306f26363643c054f64d62a9acb39151e..214d44aef35b5cd69ffe859138938e311c717cc3 100644 (file)
@@ -207,7 +207,7 @@ found:
        } else {
                fq->q.meat += skb->len;
        }
-       add_frag_mem_limit(&fq->q, skb->truesize);
+       add_frag_mem_limit(fq->q.net, skb->truesize);
 
        if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
            fq->q.meat == fq->q.len) {
@@ -287,7 +287,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev,
                clone->data_len = clone->len;
                head->data_len -= clone->len;
                head->len -= clone->len;
-               add_frag_mem_limit(&fq->q, clone->truesize);
+               add_frag_mem_limit(fq->q.net, clone->truesize);
        }
 
        WARN_ON(head == NULL);
@@ -310,7 +310,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev,
                }
                fp = next;
        }
-       sub_frag_mem_limit(&fq->q, sum_truesize);
+       sub_frag_mem_limit(fq->q.net, sum_truesize);
 
        head->next = NULL;
        head->dev = dev;
index 933a92820d265e07b8c42300c7be6742565723b5..6c8b1fbafce8e39cb7c4c058fa653dd9d2f52f9e 100644 (file)
@@ -1017,14 +1017,16 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)
 
        neigh = neigh_lookup(&arp_tbl, &ip, dev);
        if (neigh) {
-               read_lock_bh(&neigh->lock);
-               memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len);
-               r->arp_flags = arp_state_to_flags(neigh);
-               read_unlock_bh(&neigh->lock);
-               r->arp_ha.sa_family = dev->type;
-               strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev));
+               if (!(neigh->nud_state & NUD_NOARP)) {
+                       read_lock_bh(&neigh->lock);
+                       memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len);
+                       r->arp_flags = arp_state_to_flags(neigh);
+                       read_unlock_bh(&neigh->lock);
+                       r->arp_ha.sa_family = dev->type;
+                       strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev));
+                       err = 0;
+               }
                neigh_release(neigh);
-               err = 0;
        }
        return err;
 }
index 90c0e8386116177f4bbf412f2175aec93c64870c..574fad9cca052cb2970e283a4dc5568c4b3b8b23 100644 (file)
@@ -20,7 +20,7 @@
 #include <net/route.h>
 #include <net/tcp_states.h>
 
-int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct inet_sock *inet = inet_sk(sk);
        struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
@@ -39,8 +39,6 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 
        sk_dst_reset(sk);
 
-       lock_sock(sk);
-
        oif = sk->sk_bound_dev_if;
        saddr = inet->inet_saddr;
        if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
@@ -82,9 +80,19 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        sk_dst_set(sk, &rt->dst);
        err = 0;
 out:
-       release_sock(sk);
        return err;
 }
+EXPORT_SYMBOL(__ip4_datagram_connect);
+
+int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+       int res;
+
+       lock_sock(sk);
+       res = __ip4_datagram_connect(sk, uaddr, addr_len);
+       release_sock(sk);
+       return res;
+}
 EXPORT_SYMBOL(ip4_datagram_connect);
 
 /* Because UDP xmit path can manipulate sk_dst_cache without holding
index e813196c91c76a66cc2eb272064d484734bd7497..2d9cb1748f8191c785567632faf0ee14eaca628b 100644 (file)
@@ -882,7 +882,6 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
                queue_delayed_work(system_power_efficient_wq,
                                &check_lifetime_work, 0);
                rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
-               blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
        }
        return 0;
 }
index c6211ed60b03be1940a1954c08adb8a265f4e124..9c02920725dbea00d2a4f84877e0769ff74cfe0c 100644 (file)
@@ -13,6 +13,7 @@ struct fib_alias {
        u8                      fa_state;
        u8                      fa_slen;
        u32                     tb_id;
+       s16                     fa_default;
        struct rcu_head         rcu;
 };
 
index c7358ea4ae93530a7f6ef110a2dc204f19ac830e..3a06586b170c0947ef62ecc08a5dcf1a1c768011 100644 (file)
@@ -1202,23 +1202,40 @@ int fib_sync_down_dev(struct net_device *dev, unsigned long event)
 }
 
 /* Must be invoked inside of an RCU protected region.  */
-void fib_select_default(struct fib_result *res)
+void fib_select_default(const struct flowi4 *flp, struct fib_result *res)
 {
        struct fib_info *fi = NULL, *last_resort = NULL;
        struct hlist_head *fa_head = res->fa_head;
        struct fib_table *tb = res->table;
+       u8 slen = 32 - res->prefixlen;
        int order = -1, last_idx = -1;
-       struct fib_alias *fa;
+       struct fib_alias *fa, *fa1 = NULL;
+       u32 last_prio = res->fi->fib_priority;
+       u8 last_tos = 0;
 
        hlist_for_each_entry_rcu(fa, fa_head, fa_list) {
                struct fib_info *next_fi = fa->fa_info;
 
+               if (fa->fa_slen != slen)
+                       continue;
+               if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
+                       continue;
+               if (fa->tb_id != tb->tb_id)
+                       continue;
+               if (next_fi->fib_priority > last_prio &&
+                   fa->fa_tos == last_tos) {
+                       if (last_tos)
+                               continue;
+                       break;
+               }
+               if (next_fi->fib_flags & RTNH_F_DEAD)
+                       continue;
+               last_tos = fa->fa_tos;
+               last_prio = next_fi->fib_priority;
+
                if (next_fi->fib_scope != res->scope ||
                    fa->fa_type != RTN_UNICAST)
                        continue;
-
-               if (next_fi->fib_priority > res->fi->fib_priority)
-                       break;
                if (!next_fi->fib_nh[0].nh_gw ||
                    next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
                        continue;
@@ -1228,10 +1245,11 @@ void fib_select_default(struct fib_result *res)
                if (!fi) {
                        if (next_fi != res->fi)
                                break;
+                       fa1 = fa;
                } else if (!fib_detect_death(fi, order, &last_resort,
-                                            &last_idx, tb->tb_default)) {
+                                            &last_idx, fa1->fa_default)) {
                        fib_result_assign(res, fi);
-                       tb->tb_default = order;
+                       fa1->fa_default = order;
                        goto out;
                }
                fi = next_fi;
@@ -1239,20 +1257,21 @@ void fib_select_default(struct fib_result *res)
        }
 
        if (order <= 0 || !fi) {
-               tb->tb_default = -1;
+               if (fa1)
+                       fa1->fa_default = -1;
                goto out;
        }
 
        if (!fib_detect_death(fi, order, &last_resort, &last_idx,
-                               tb->tb_default)) {
+                             fa1->fa_default)) {
                fib_result_assign(res, fi);
-               tb->tb_default = order;
+               fa1->fa_default = order;
                goto out;
        }
 
        if (last_idx >= 0)
                fib_result_assign(res, last_resort);
-       tb->tb_default = last_idx;
+       fa1->fa_default = last_idx;
 out:
        return;
 }
index 15d32612e3c6f134a533034aa4d7f74fa52da51b..37c4bb89a7082bbe36b40d928f7fd1d95bfe8252 100644 (file)
@@ -1171,6 +1171,7 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
                        new_fa->fa_state = state & ~FA_S_ACCESSED;
                        new_fa->fa_slen = fa->fa_slen;
                        new_fa->tb_id = tb->tb_id;
+                       new_fa->fa_default = -1;
 
                        err = switchdev_fib_ipv4_add(key, plen, fi,
                                                     new_fa->fa_tos,
@@ -1222,6 +1223,7 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
        new_fa->fa_state = 0;
        new_fa->fa_slen = slen;
        new_fa->tb_id = tb->tb_id;
+       new_fa->fa_default = -1;
 
        /* (Optionally) offload fib entry to switch hardware. */
        err = switchdev_fib_ipv4_add(key, plen, fi, tos, cfg->fc_type,
@@ -1791,8 +1793,6 @@ void fib_table_flush_external(struct fib_table *tb)
                if (hlist_empty(&n->leaf)) {
                        put_child_root(pn, n->key, NULL);
                        node_free(n);
-               } else {
-                       leaf_pull_suffix(pn, n);
                }
        }
 }
@@ -1862,8 +1862,6 @@ int fib_table_flush(struct fib_table *tb)
                if (hlist_empty(&n->leaf)) {
                        put_child_root(pn, n->key, NULL);
                        node_free(n);
-               } else {
-                       leaf_pull_suffix(pn, n);
                }
        }
 
@@ -1990,7 +1988,6 @@ struct fib_table *fib_trie_table(u32 id, struct fib_table *alias)
                return NULL;
 
        tb->tb_id = id;
-       tb->tb_default = -1;
        tb->tb_num_default = 0;
        tb->tb_data = (alias ? alias->__data : tb->__data);
 
index 60021d0d9326ac691dcef21e1f9c20de5f8fe7c6..05e3145f7dc346af56a50b945dc75d6f1bdb27c7 100644 (file)
@@ -593,7 +593,7 @@ static bool reqsk_queue_unlink(struct request_sock_queue *queue,
        }
 
        spin_unlock(&queue->syn_wait_lock);
-       if (del_timer(&req->rsk_timer))
+       if (del_timer_sync(&req->rsk_timer))
                reqsk_put(req);
        return found;
 }
index 5e346a082e5ff05b58cfebb64917ee26001d809d..d0a7c0319e3d1b1b73f828717062b6fbbd3be27d 100644 (file)
@@ -131,34 +131,22 @@ inet_evict_bucket(struct inet_frags *f, struct inet_frag_bucket *hb)
        unsigned int evicted = 0;
        HLIST_HEAD(expired);
 
-evict_again:
        spin_lock(&hb->chain_lock);
 
        hlist_for_each_entry_safe(fq, n, &hb->chain, list) {
                if (!inet_fragq_should_evict(fq))
                        continue;
 
-               if (!del_timer(&fq->timer)) {
-                       /* q expiring right now thus increment its refcount so
-                        * it won't be freed under us and wait until the timer
-                        * has finished executing then destroy it
-                        */
-                       atomic_inc(&fq->refcnt);
-                       spin_unlock(&hb->chain_lock);
-                       del_timer_sync(&fq->timer);
-                       inet_frag_put(fq, f);
-                       goto evict_again;
-               }
+               if (!del_timer(&fq->timer))
+                       continue;
 
-               fq->flags |= INET_FRAG_EVICTED;
-               hlist_del(&fq->list);
-               hlist_add_head(&fq->list, &expired);
+               hlist_add_head(&fq->list_evictor, &expired);
                ++evicted;
        }
 
        spin_unlock(&hb->chain_lock);
 
-       hlist_for_each_entry_safe(fq, n, &expired, list)
+       hlist_for_each_entry_safe(fq, n, &expired, list_evictor)
                f->frag_expire((unsigned long) fq);
 
        return evicted;
@@ -240,18 +228,20 @@ void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f)
        int i;
 
        nf->low_thresh = 0;
-       local_bh_disable();
 
 evict_again:
+       local_bh_disable();
        seq = read_seqbegin(&f->rnd_seqlock);
 
        for (i = 0; i < INETFRAGS_HASHSZ ; i++)
                inet_evict_bucket(f, &f->hash[i]);
 
-       if (read_seqretry(&f->rnd_seqlock, seq))
-               goto evict_again;
-
        local_bh_enable();
+       cond_resched();
+
+       if (read_seqretry(&f->rnd_seqlock, seq) ||
+           percpu_counter_sum(&nf->mem))
+               goto evict_again;
 
        percpu_counter_destroy(&nf->mem);
 }
@@ -284,8 +274,8 @@ static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f)
        struct inet_frag_bucket *hb;
 
        hb = get_frag_bucket_locked(fq, f);
-       if (!(fq->flags & INET_FRAG_EVICTED))
-               hlist_del(&fq->list);
+       hlist_del(&fq->list);
+       fq->flags |= INET_FRAG_COMPLETE;
        spin_unlock(&hb->chain_lock);
 }
 
@@ -297,7 +287,6 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
        if (!(fq->flags & INET_FRAG_COMPLETE)) {
                fq_unlink(fq, f);
                atomic_dec(&fq->refcnt);
-               fq->flags |= INET_FRAG_COMPLETE;
        }
 }
 EXPORT_SYMBOL(inet_frag_kill);
@@ -330,11 +319,12 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f)
                fp = xp;
        }
        sum = sum_truesize + f->qsize;
-       sub_frag_mem_limit(q, sum);
 
        if (f->destructor)
                f->destructor(q);
        kmem_cache_free(f->frags_cachep, q);
+
+       sub_frag_mem_limit(nf, sum);
 }
 EXPORT_SYMBOL(inet_frag_destroy);
 
@@ -390,7 +380,7 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf,
 
        q->net = nf;
        f->constructor(q, arg);
-       add_frag_mem_limit(q, f->qsize);
+       add_frag_mem_limit(nf, f->qsize);
 
        setup_timer(&q->timer, f->frag_expire, (unsigned long)q);
        spin_lock_init(&q->lock);
index 5f9b063bbe8ab4f3755a5711ae19b816a3bc2026..0cb9165421d450ae8f6aff81b88ef4bf2839ff51 100644 (file)
@@ -624,22 +624,21 @@ EXPORT_SYMBOL_GPL(inet_hashinfo_init);
 
 int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo)
 {
+       unsigned int locksz = sizeof(spinlock_t);
        unsigned int i, nblocks = 1;
 
-       if (sizeof(spinlock_t) != 0) {
+       if (locksz != 0) {
                /* allocate 2 cache lines or at least one spinlock per cpu */
-               nblocks = max_t(unsigned int,
-                               2 * L1_CACHE_BYTES / sizeof(spinlock_t),
-                               1);
+               nblocks = max(2U * L1_CACHE_BYTES / locksz, 1U);
                nblocks = roundup_pow_of_two(nblocks * num_possible_cpus());
 
                /* no more locks than number of hash buckets */
                nblocks = min(nblocks, hashinfo->ehash_mask + 1);
 
-               hashinfo->ehash_locks = kmalloc_array(nblocks, sizeof(spinlock_t),
+               hashinfo->ehash_locks = kmalloc_array(nblocks, locksz,
                                                      GFP_KERNEL | __GFP_NOWARN);
                if (!hashinfo->ehash_locks)
-                       hashinfo->ehash_locks = vmalloc(nblocks * sizeof(spinlock_t));
+                       hashinfo->ehash_locks = vmalloc(nblocks * locksz);
 
                if (!hashinfo->ehash_locks)
                        return -ENOMEM;
index a50dc6d408d11c339b38f2436216c8568c4149cf..921138f6c97c9948a7cf5e2e36b7e3dbfabc6e29 100644 (file)
@@ -202,7 +202,7 @@ static void ip_expire(unsigned long arg)
        ipq_kill(qp);
        IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
 
-       if (!(qp->q.flags & INET_FRAG_EVICTED)) {
+       if (!inet_frag_evicting(&qp->q)) {
                struct sk_buff *head = qp->q.fragments;
                const struct iphdr *iph;
                int err;
@@ -309,7 +309,7 @@ static int ip_frag_reinit(struct ipq *qp)
                kfree_skb(fp);
                fp = xp;
        } while (fp);
-       sub_frag_mem_limit(&qp->q, sum_truesize);
+       sub_frag_mem_limit(qp->q.net, sum_truesize);
 
        qp->q.flags = 0;
        qp->q.len = 0;
@@ -351,7 +351,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
        ihl = ip_hdrlen(skb);
 
        /* Determine the position of this fragment. */
-       end = offset + skb->len - ihl;
+       end = offset + skb->len - skb_network_offset(skb) - ihl;
        err = -EINVAL;
 
        /* Is this the final fragment? */
@@ -381,7 +381,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
                goto err;
 
        err = -ENOMEM;
-       if (!pskb_pull(skb, ihl))
+       if (!pskb_pull(skb, skb_network_offset(skb) + ihl))
                goto err;
 
        err = pskb_trim_rcsum(skb, end - offset);
@@ -455,7 +455,7 @@ found:
                                qp->q.fragments = next;
 
                        qp->q.meat -= free_it->len;
-                       sub_frag_mem_limit(&qp->q, free_it->truesize);
+                       sub_frag_mem_limit(qp->q.net, free_it->truesize);
                        kfree_skb(free_it);
                }
        }
@@ -479,7 +479,7 @@ found:
        qp->q.stamp = skb->tstamp;
        qp->q.meat += skb->len;
        qp->ecn |= ecn;
-       add_frag_mem_limit(&qp->q, skb->truesize);
+       add_frag_mem_limit(qp->q.net, skb->truesize);
        if (offset == 0)
                qp->q.flags |= INET_FRAG_FIRST_IN;
 
@@ -587,7 +587,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                head->len -= clone->len;
                clone->csum = 0;
                clone->ip_summed = head->ip_summed;
-               add_frag_mem_limit(&qp->q, clone->truesize);
+               add_frag_mem_limit(qp->q.net, clone->truesize);
        }
 
        skb_push(head, head->data - skb_network_header(head));
@@ -615,7 +615,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                }
                fp = next;
        }
-       sub_frag_mem_limit(&qp->q, sum_truesize);
+       sub_frag_mem_limit(qp->q.net, sum_truesize);
 
        head->next = NULL;
        head->dev = dev;
@@ -641,6 +641,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                iph->frag_off = 0;
        }
 
+       ip_send_check(iph);
+
        IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
        qp->q.fragments = NULL;
        qp->q.fragments_tail = NULL;
index fe8cc183411e052f6e0ba4afefbeaef1e77313cd..95ea633e8356eb9b419e4027f9954810194aa23c 100644 (file)
@@ -226,7 +226,8 @@ synproxy_send_client_ack(const struct synproxy_net *snet,
 
        synproxy_build_options(nth, opts);
 
-       synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
+       synproxy_send_tcp(skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
+                         niph, nth, tcp_hdr_size);
 }
 
 static bool
index d0362a2de3d3805260c878f5e3a9341e225cade9..e681b852ced1d0c0cde984496d832d9cf3f7fad2 100644 (file)
@@ -2176,7 +2176,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
        if (!res.prefixlen &&
            res.table->tb_num_default > 1 &&
            res.type == RTN_UNICAST && !fl4->flowi4_oif)
-               fib_select_default(&res);
+               fib_select_default(fl4, &res);
 
        if (!fl4->saddr)
                fl4->saddr = FIB_RES_PREFSRC(net, res);
index 7f4056785accb76eec60e22dc0bb19febc98f75f..45534a5ab43065307bfe2708a5ae08936cc5969a 100644 (file)
@@ -780,7 +780,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
                                ret = -EAGAIN;
                                break;
                        }
-                       sk_wait_data(sk, &timeo);
+                       sk_wait_data(sk, &timeo, NULL);
                        if (signal_pending(current)) {
                                ret = sock_intr_errno(timeo);
                                break;
@@ -1575,7 +1575,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
        int target;             /* Read at least this many bytes */
        long timeo;
        struct task_struct *user_recv = NULL;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *last;
        u32 urg_hole = 0;
 
        if (unlikely(flags & MSG_ERRQUEUE))
@@ -1635,7 +1635,9 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
 
                /* Next get a buffer. */
 
+               last = skb_peek_tail(&sk->sk_receive_queue);
                skb_queue_walk(&sk->sk_receive_queue, skb) {
+                       last = skb;
                        /* Now that we have two receive queues this
                         * shouldn't happen.
                         */
@@ -1754,8 +1756,9 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
                        /* Do not sleep, just process backlog. */
                        release_sock(sk);
                        lock_sock(sk);
-               } else
-                       sk_wait_data(sk, &timeo);
+               } else {
+                       sk_wait_data(sk, &timeo, last);
+               }
 
                if (user_recv) {
                        int chunk;
index 684f095d196e20333adb235fc96a8fb8f0dd691c..728f5b3d3c64197bb526240a078744d5a950c8ea 100644 (file)
@@ -1917,14 +1917,13 @@ void tcp_enter_loss(struct sock *sk)
        const struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
-       bool new_recovery = false;
+       bool new_recovery = icsk->icsk_ca_state < TCP_CA_Recovery;
        bool is_reneg;                  /* is receiver reneging on SACKs? */
 
        /* Reduce ssthresh if it has not yet been made inside this window. */
        if (icsk->icsk_ca_state <= TCP_CA_Disorder ||
            !after(tp->high_seq, tp->snd_una) ||
            (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) {
-               new_recovery = true;
                tp->prior_ssthresh = tcp_current_ssthresh(sk);
                tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
                tcp_ca_event(sk, CA_EVENT_LOSS);
index d7d4c2b79cf2f516f9e3f62c6fe4415e9bc137a0..0ea2e1c5d395ac979e9a301d006867d49b866ecb 100644 (file)
@@ -1348,7 +1348,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
        req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr);
        if (req) {
                nsk = tcp_check_req(sk, skb, req, false);
-               if (!nsk)
+               if (!nsk || nsk == sk)
                        reqsk_put(req);
                return nsk;
        }
index 83aa604f9273c332c5a0e5399253d961ef92eb9a..1b8c5ba7d5f732ea2220ada929049c5c7cfd5e83 100644 (file)
@@ -1995,12 +1995,19 @@ void udp_v4_early_demux(struct sk_buff *skb)
 
        skb->sk = sk;
        skb->destructor = sock_efree;
-       dst = sk->sk_rx_dst;
+       dst = READ_ONCE(sk->sk_rx_dst);
 
        if (dst)
                dst = dst_check(dst, 0);
-       if (dst)
-               skb_dst_set_noref(skb, dst);
+       if (dst) {
+               /* DST_NOCACHE can not be used without taking a reference */
+               if (dst->flags & DST_NOCACHE) {
+                       if (likely(atomic_inc_not_zero(&dst->__refcnt)))
+                               skb_dst_set(skb, dst);
+               } else {
+                       skb_dst_set_noref(skb, dst);
+               }
+       }
 }
 
 int udp_rcv(struct sk_buff *skb)
index 62d908e64eeb53740d53ddfd57e26867c4e7e4d3..b10a88986a9896a4a33f8a4139e41d3f1013a41a 100644 (file)
@@ -40,7 +40,7 @@ static bool ipv6_mapped_addr_any(const struct in6_addr *a)
        return ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0);
 }
 
-int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
        struct inet_sock        *inet = inet_sk(sk);
@@ -56,7 +56,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        if (usin->sin6_family == AF_INET) {
                if (__ipv6_only_sock(sk))
                        return -EAFNOSUPPORT;
-               err = ip4_datagram_connect(sk, uaddr, addr_len);
+               err = __ip4_datagram_connect(sk, uaddr, addr_len);
                goto ipv4_connected;
        }
 
@@ -98,9 +98,9 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                sin.sin_addr.s_addr = daddr->s6_addr32[3];
                sin.sin_port = usin->sin6_port;
 
-               err = ip4_datagram_connect(sk,
-                                          (struct sockaddr *) &sin,
-                                          sizeof(sin));
+               err = __ip4_datagram_connect(sk,
+                                            (struct sockaddr *) &sin,
+                                            sizeof(sin));
 
 ipv4_connected:
                if (err)
@@ -204,6 +204,16 @@ out:
        fl6_sock_release(flowlabel);
        return err;
 }
+
+int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+       int res;
+
+       lock_sock(sk);
+       res = __ip6_datagram_connect(sk, uaddr, addr_len);
+       release_sock(sk);
+       return res;
+}
 EXPORT_SYMBOL_GPL(ip6_datagram_connect);
 
 int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr,
index e893cd18612fcdc9e8577f0e060ffd32b5659eea..08b62047c67f311ca808533cb7a83b5caab0cfc8 100644 (file)
@@ -292,8 +292,6 @@ static struct packet_offload ipv6_packet_offload __read_mostly = {
 static const struct net_offload sit_offload = {
        .callbacks = {
                .gso_segment    = ipv6_gso_segment,
-               .gro_receive    = ipv6_gro_receive,
-               .gro_complete   = ipv6_gro_complete,
        },
 };
 
index 0a05b35a90fc946dc0de3ae76e4a682ca4438932..c53331cfed95dcbb6672b80282125516e904a84f 100644 (file)
@@ -1650,6 +1650,7 @@ int ndisc_rcv(struct sk_buff *skb)
 static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct netdev_notifier_change_info *change_info;
        struct net *net = dev_net(dev);
        struct inet6_dev *idev;
 
@@ -1664,6 +1665,11 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
                        ndisc_send_unsol_na(dev);
                in6_dev_put(idev);
                break;
+       case NETDEV_CHANGE:
+               change_info = ptr;
+               if (change_info->flags_changed & IFF_NOARP)
+                       neigh_changeaddr(&nd_tbl, dev);
+               break;
        case NETDEV_DOWN:
                neigh_ifdown(&nd_tbl, dev);
                fib6_run_gc(0, net, false);
index 6edb7b106de769728357174d0657c644f83e41e8..ebbb754c2111b73c87fe85aa58b3124e0a3032ef 100644 (file)
@@ -37,12 +37,13 @@ synproxy_build_ip(struct sk_buff *skb, const struct in6_addr *saddr,
 }
 
 static void
-synproxy_send_tcp(const struct sk_buff *skb, struct sk_buff *nskb,
+synproxy_send_tcp(const struct synproxy_net *snet,
+                 const struct sk_buff *skb, struct sk_buff *nskb,
                  struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
                  struct ipv6hdr *niph, struct tcphdr *nth,
                  unsigned int tcp_hdr_size)
 {
-       struct net *net = nf_ct_net((struct nf_conn *)nfct);
+       struct net *net = nf_ct_net(snet->tmpl);
        struct dst_entry *dst;
        struct flowi6 fl6;
 
@@ -83,7 +84,8 @@ free_nskb:
 }
 
 static void
-synproxy_send_client_synack(const struct sk_buff *skb, const struct tcphdr *th,
+synproxy_send_client_synack(const struct synproxy_net *snet,
+                           const struct sk_buff *skb, const struct tcphdr *th,
                            const struct synproxy_options *opts)
 {
        struct sk_buff *nskb;
@@ -119,7 +121,7 @@ synproxy_send_client_synack(const struct sk_buff *skb, const struct tcphdr *th,
 
        synproxy_build_options(nth, opts);
 
-       synproxy_send_tcp(skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
+       synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
                          niph, nth, tcp_hdr_size);
 }
 
@@ -163,7 +165,7 @@ synproxy_send_server_syn(const struct synproxy_net *snet,
 
        synproxy_build_options(nth, opts);
 
-       synproxy_send_tcp(skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
+       synproxy_send_tcp(snet, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
                          niph, nth, tcp_hdr_size);
 }
 
@@ -203,7 +205,7 @@ synproxy_send_server_ack(const struct synproxy_net *snet,
 
        synproxy_build_options(nth, opts);
 
-       synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
+       synproxy_send_tcp(snet, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
 }
 
 static void
@@ -241,7 +243,8 @@ synproxy_send_client_ack(const struct synproxy_net *snet,
 
        synproxy_build_options(nth, opts);
 
-       synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
+       synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
+                         niph, nth, tcp_hdr_size);
 }
 
 static bool
@@ -301,7 +304,7 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
                                          XT_SYNPROXY_OPT_SACK_PERM |
                                          XT_SYNPROXY_OPT_ECN);
 
-               synproxy_send_client_synack(skb, th, &opts);
+               synproxy_send_client_synack(snet, skb, th, &opts);
                return NF_DROP;
 
        } else if (th->ack && !(th->fin || th->rst || th->syn)) {
index 6f187c8d8a1bdf4ab27ec71ea05e865fcf782371..6d02498172c168f2716e3b71a29e3b082a93dcfb 100644 (file)
@@ -348,7 +348,7 @@ found:
        fq->ecn |= ecn;
        if (payload_len > fq->q.max_size)
                fq->q.max_size = payload_len;
-       add_frag_mem_limit(&fq->q, skb->truesize);
+       add_frag_mem_limit(fq->q.net, skb->truesize);
 
        /* The first fragment.
         * nhoffset is obtained from the first fragment, of course.
@@ -430,7 +430,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
                clone->ip_summed = head->ip_summed;
 
                NFCT_FRAG6_CB(clone)->orig = NULL;
-               add_frag_mem_limit(&fq->q, clone->truesize);
+               add_frag_mem_limit(fq->q.net, clone->truesize);
        }
 
        /* We have to remove fragment header from datagram and to relocate
@@ -454,7 +454,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
                        head->csum = csum_add(head->csum, fp->csum);
                head->truesize += fp->truesize;
        }
-       sub_frag_mem_limit(&fq->q, head->truesize);
+       sub_frag_mem_limit(fq->q.net, head->truesize);
 
        head->ignore_df = 1;
        head->next = NULL;
index 8ffa2c8cce774e8398a031ab90c69a3ed2934a6a..f1159bb76e0a54fb55a3e8e382a6cb80c7a929f9 100644 (file)
@@ -144,7 +144,7 @@ void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq,
 
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
 
-       if (fq->q.flags & INET_FRAG_EVICTED)
+       if (inet_frag_evicting(&fq->q))
                goto out_rcu_unlock;
 
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
@@ -330,7 +330,7 @@ found:
        fq->q.stamp = skb->tstamp;
        fq->q.meat += skb->len;
        fq->ecn |= ecn;
-       add_frag_mem_limit(&fq->q, skb->truesize);
+       add_frag_mem_limit(fq->q.net, skb->truesize);
 
        /* The first fragment.
         * nhoffset is obtained from the first fragment, of course.
@@ -443,7 +443,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                head->len -= clone->len;
                clone->csum = 0;
                clone->ip_summed = head->ip_summed;
-               add_frag_mem_limit(&fq->q, clone->truesize);
+               add_frag_mem_limit(fq->q.net, clone->truesize);
        }
 
        /* We have to remove fragment header from datagram and to relocate
@@ -481,7 +481,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                }
                fp = next;
        }
-       sub_frag_mem_limit(&fq->q, sum_truesize);
+       sub_frag_mem_limit(fq->q.net, sum_truesize);
 
        head->next = NULL;
        head->dev = dev;
index 6090969937f8b6809f74c3d03f29a0703089eff1..9de4d2bcd9168cc0c8951f1042e77754979bab62 100644 (file)
@@ -1831,6 +1831,7 @@ int ip6_route_add(struct fib6_config *cfg)
                int gwa_type;
 
                gw_addr = &cfg->fc_gateway;
+               gwa_type = ipv6_addr_type(gw_addr);
 
                /* if gw_addr is local we will fail to detect this in case
                 * address is still TENTATIVE (DAD in progress). rt6_lookup()
@@ -1838,11 +1839,12 @@ int ip6_route_add(struct fib6_config *cfg)
                 * prefix route was assigned to, which might be non-loopback.
                 */
                err = -EINVAL;
-               if (ipv6_chk_addr_and_flags(net, gw_addr, NULL, 0, 0))
+               if (ipv6_chk_addr_and_flags(net, gw_addr,
+                                           gwa_type & IPV6_ADDR_LINKLOCAL ?
+                                           dev : NULL, 0, 0))
                        goto out;
 
                rt->rt6i_gateway = *gw_addr;
-               gwa_type = ipv6_addr_type(gw_addr);
 
                if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
                        struct rt6_info *grt;
index 6748c4277affad71cd721e3a985af10c31c047ad..7a6cea5e427414062f408cfa66f57808d48382d7 100644 (file)
@@ -943,7 +943,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
                                   &ipv6_hdr(skb)->daddr, tcp_v6_iif(skb));
        if (req) {
                nsk = tcp_check_req(sk, skb, req, false);
-               if (!nsk)
+               if (!nsk || nsk == sk)
                        reqsk_put(req);
                return nsk;
        }
index 8fd9febaa5bad8150bdf632b97221a140e0e3cbd..8dab4e569571dd34096104f87e8ed27faa7d5522 100644 (file)
@@ -613,7 +613,7 @@ static int llc_wait_data(struct sock *sk, long timeo)
                if (signal_pending(current))
                        break;
                rc = 0;
-               if (sk_wait_data(sk, &timeo))
+               if (sk_wait_data(sk, &timeo, NULL))
                        break;
        }
        return rc;
@@ -802,7 +802,7 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                        release_sock(sk);
                        lock_sock(sk);
                } else
-                       sk_wait_data(sk, &timeo);
+                       sk_wait_data(sk, &timeo, NULL);
 
                if ((flags & MSG_PEEK) && peek_seq != llc->copied_seq) {
                        net_dbg_ratelimited("LLC(%s:%d): Application bug, race in MSG_PEEK\n",
index 29236e832e44470a4f13637847c2d1cbafb9bfb2..c09c0131bfa227e99346b180f501cc6fcf64644a 100644 (file)
@@ -723,6 +723,7 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
 
        debugfs_remove_recursive(sdata->vif.debugfs_dir);
        sdata->vif.debugfs_dir = NULL;
+       sdata->debugfs.subdir_stations = NULL;
 }
 
 void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
index ed1edac143729cc117c1cb63c5519285acff13a7..553ac6dd4867480048aed3ca0d430948f928d3c7 100644 (file)
@@ -1863,10 +1863,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
        ieee80211_teardown_sdata(sdata);
 }
 
-/*
- * Remove all interfaces, may only be called at hardware unregistration
- * time because it doesn't do RCU-safe list removals.
- */
 void ieee80211_remove_interfaces(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata, *tmp;
@@ -1875,14 +1871,21 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
 
        ASSERT_RTNL();
 
-       /*
-        * Close all AP_VLAN interfaces first, as otherwise they
-        * might be closed while the AP interface they belong to
-        * is closed, causing unregister_netdevice_many() to crash.
+       /* Before destroying the interfaces, make sure they're all stopped so
+        * that the hardware is stopped. Otherwise, the driver might still be
+        * iterating the interfaces during the shutdown, e.g. from a worker
+        * or from RX processing or similar, and if it does so (using atomic
+        * iteration) while we're manipulating the list, the iteration will
+        * crash.
+        *
+        * After this, the hardware should be stopped and the driver should
+        * have stopped all of its activities, so that we can do RCU-unaware
+        * manipulations of the interface list below.
         */
-       list_for_each_entry(sdata, &local->interfaces, list)
-               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-                       dev_close(sdata->dev);
+       cfg80211_shutdown_all_interfaces(local->hw.wiphy);
+
+       WARN(local->open_count, "%s: open count remains %d\n",
+            wiphy_name(local->hw.wiphy), local->open_count);
 
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
index 5438d13e2f007d1bca01ac97bb0f54867bef15ce..3b59099413fb1770e2ee2228065899bc5f9eb302 100644 (file)
@@ -306,7 +306,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
                        /* AID */
                        pos = skb_put(skb, 2);
-                       put_unaligned_le16(plid, pos + 2);
+                       put_unaligned_le16(plid, pos);
                }
                if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
                    ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
@@ -1122,6 +1122,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
                                                WLAN_SP_MESH_PEERING_CONFIRM) {
                baseaddr += 4;
                baselen += 4;
+
+               if (baselen > len)
+                       return;
        }
        ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
        mesh_process_plink_frame(sdata, mgmt, &elems);
index 06b60980c62c62cf8c8f95e10052060be5d36ed8..b676b9fa707b3c8872a1065d8582b8ff1463e607 100644 (file)
@@ -76,6 +76,22 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                                continue;
                        ieee80211_mgd_quiesce(sdata);
+                       /* If suspended during TX in progress, and wowlan
+                        * is enabled (connection will be active) there
+                        * can be a race where the driver is put out
+                        * of power-save due to TX and during suspend
+                        * dynamic_ps_timer is cancelled and TX packet
+                        * is flushed, leaving the driver in ACTIVE even
+                        * after resuming until dynamic_ps_timer puts
+                        * driver back in DOZE.
+                        */
+                       if (sdata->u.mgd.associated &&
+                           sdata->u.mgd.powersave &&
+                            !(local->hw.conf.flags & IEEE80211_CONF_PS)) {
+                               local->hw.conf.flags |= IEEE80211_CONF_PS;
+                               ieee80211_hw_config(local,
+                                                   IEEE80211_CONF_CHANGE_PS);
+                       }
                }
 
                err = drv_suspend(local, wowlan);
index ad31b2dab4f5ab0731d53e54f00b30e65b085ec4..8db6e2994bbc59bb7cf38c36848a7d92b8e4a0e5 100644 (file)
@@ -60,6 +60,7 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_channel *ch;
        struct cfg80211_chan_def chandef;
        int i, subband_start;
+       struct wiphy *wiphy = sdata->local->hw.wiphy;
 
        for (i = start; i <= end; i += spacing) {
                if (!ch_cnt)
@@ -70,9 +71,8 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
                        /* we will be active on the channel */
                        cfg80211_chandef_create(&chandef, ch,
                                                NL80211_CHAN_NO_HT);
-                       if (cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
-                                                   &chandef,
-                                                   sdata->wdev.iftype)) {
+                       if (cfg80211_reg_can_beacon_relax(wiphy, &chandef,
+                                                         sdata->wdev.iftype)) {
                                ch_cnt++;
                                /*
                                 * check if the next channel is also part of
index 8410bb3bf5e8ddf5552fb0af84d05152425148dd..b8233505bf9fd3bb4945c126eebee069f2b94878 100644 (file)
@@ -1117,7 +1117,9 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
                        queued = true;
                        info->control.vif = &tx->sdata->vif;
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
-                       info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
+                       info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS |
+                                       IEEE80211_TX_CTL_NO_PS_BUFFER |
+                                       IEEE80211_TX_STATUS_EOSP;
                        __skb_queue_tail(&tid_tx->pending, skb);
                        if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
                                purge_skb = __skb_dequeue(&tid_tx->pending);
index 5d2b806a862e6834ff6c61aee5c0e0a899bbe4b8..38fbc194b9cb72835c497439713d23f16d99ca8c 100644 (file)
@@ -319,7 +319,13 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
                 * return *ignored=0 i.e. ICMP and NF_DROP
                 */
                sched = rcu_dereference(svc->scheduler);
-               dest = sched->schedule(svc, skb, iph);
+               if (sched) {
+                       /* read svc->sched_data after svc->scheduler */
+                       smp_rmb();
+                       dest = sched->schedule(svc, skb, iph);
+               } else {
+                       dest = NULL;
+               }
                if (!dest) {
                        IP_VS_DBG(1, "p-schedule: no dest found.\n");
                        kfree(param.pe_data);
@@ -467,7 +473,13 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
        }
 
        sched = rcu_dereference(svc->scheduler);
-       dest = sched->schedule(svc, skb, iph);
+       if (sched) {
+               /* read svc->sched_data after svc->scheduler */
+               smp_rmb();
+               dest = sched->schedule(svc, skb, iph);
+       } else {
+               dest = NULL;
+       }
        if (dest == NULL) {
                IP_VS_DBG(1, "Schedule: no dest found.\n");
                return NULL;
index 285eae3a145483c48c00493651a46a5d81656845..24c554201a766d175ed90359b6b78617acd37c64 100644 (file)
@@ -842,15 +842,16 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
        __ip_vs_dst_cache_reset(dest);
        spin_unlock_bh(&dest->dst_lock);
 
-       sched = rcu_dereference_protected(svc->scheduler, 1);
        if (add) {
                ip_vs_start_estimator(svc->net, &dest->stats);
                list_add_rcu(&dest->n_list, &svc->destinations);
                svc->num_dests++;
-               if (sched->add_dest)
+               sched = rcu_dereference_protected(svc->scheduler, 1);
+               if (sched && sched->add_dest)
                        sched->add_dest(svc, dest);
        } else {
-               if (sched->upd_dest)
+               sched = rcu_dereference_protected(svc->scheduler, 1);
+               if (sched && sched->upd_dest)
                        sched->upd_dest(svc, dest);
        }
 }
@@ -1084,7 +1085,7 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
                struct ip_vs_scheduler *sched;
 
                sched = rcu_dereference_protected(svc->scheduler, 1);
-               if (sched->del_dest)
+               if (sched && sched->del_dest)
                        sched->del_dest(svc, dest);
        }
 }
@@ -1175,11 +1176,14 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
        ip_vs_use_count_inc();
 
        /* Lookup the scheduler by 'u->sched_name' */
-       sched = ip_vs_scheduler_get(u->sched_name);
-       if (sched == NULL) {
-               pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name);
-               ret = -ENOENT;
-               goto out_err;
+       if (strcmp(u->sched_name, "none")) {
+               sched = ip_vs_scheduler_get(u->sched_name);
+               if (!sched) {
+                       pr_info("Scheduler module ip_vs_%s not found\n",
+                               u->sched_name);
+                       ret = -ENOENT;
+                       goto out_err;
+               }
        }
 
        if (u->pe_name && *u->pe_name) {
@@ -1240,10 +1244,12 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
        spin_lock_init(&svc->stats.lock);
 
        /* Bind the scheduler */
-       ret = ip_vs_bind_scheduler(svc, sched);
-       if (ret)
-               goto out_err;
-       sched = NULL;
+       if (sched) {
+               ret = ip_vs_bind_scheduler(svc, sched);
+               if (ret)
+                       goto out_err;
+               sched = NULL;
+       }
 
        /* Bind the ct retriever */
        RCU_INIT_POINTER(svc->pe, pe);
@@ -1291,17 +1297,20 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
 static int
 ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
 {
-       struct ip_vs_scheduler *sched, *old_sched;
+       struct ip_vs_scheduler *sched = NULL, *old_sched;
        struct ip_vs_pe *pe = NULL, *old_pe = NULL;
        int ret = 0;
 
        /*
         * Lookup the scheduler, by 'u->sched_name'
         */
-       sched = ip_vs_scheduler_get(u->sched_name);
-       if (sched == NULL) {
-               pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name);
-               return -ENOENT;
+       if (strcmp(u->sched_name, "none")) {
+               sched = ip_vs_scheduler_get(u->sched_name);
+               if (!sched) {
+                       pr_info("Scheduler module ip_vs_%s not found\n",
+                               u->sched_name);
+                       return -ENOENT;
+               }
        }
        old_sched = sched;
 
@@ -1329,14 +1338,20 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
 
        old_sched = rcu_dereference_protected(svc->scheduler, 1);
        if (sched != old_sched) {
+               if (old_sched) {
+                       ip_vs_unbind_scheduler(svc, old_sched);
+                       RCU_INIT_POINTER(svc->scheduler, NULL);
+                       /* Wait all svc->sched_data users */
+                       synchronize_rcu();
+               }
                /* Bind the new scheduler */
-               ret = ip_vs_bind_scheduler(svc, sched);
-               if (ret) {
-                       old_sched = sched;
-                       goto out;
+               if (sched) {
+                       ret = ip_vs_bind_scheduler(svc, sched);
+                       if (ret) {
+                               ip_vs_scheduler_put(sched);
+                               goto out;
+                       }
                }
-               /* Unbind the old scheduler on success */
-               ip_vs_unbind_scheduler(svc, old_sched);
        }
 
        /*
@@ -1982,6 +1997,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
                const struct ip_vs_iter *iter = seq->private;
                const struct ip_vs_dest *dest;
                struct ip_vs_scheduler *sched = rcu_dereference(svc->scheduler);
+               char *sched_name = sched ? sched->name : "none";
 
                if (iter->table == ip_vs_svc_table) {
 #ifdef CONFIG_IP_VS_IPV6
@@ -1990,18 +2006,18 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
                                           ip_vs_proto_name(svc->protocol),
                                           &svc->addr.in6,
                                           ntohs(svc->port),
-                                          sched->name);
+                                          sched_name);
                        else
 #endif
                                seq_printf(seq, "%s  %08X:%04X %s %s ",
                                           ip_vs_proto_name(svc->protocol),
                                           ntohl(svc->addr.ip),
                                           ntohs(svc->port),
-                                          sched->name,
+                                          sched_name,
                                           (svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
                } else {
                        seq_printf(seq, "FWM  %08X %s %s",
-                                  svc->fwmark, sched->name,
+                                  svc->fwmark, sched_name,
                                   (svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
                }
 
@@ -2427,13 +2443,15 @@ ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
 {
        struct ip_vs_scheduler *sched;
        struct ip_vs_kstats kstats;
+       char *sched_name;
 
        sched = rcu_dereference_protected(src->scheduler, 1);
+       sched_name = sched ? sched->name : "none";
        dst->protocol = src->protocol;
        dst->addr = src->addr.ip;
        dst->port = src->port;
        dst->fwmark = src->fwmark;
-       strlcpy(dst->sched_name, sched->name, sizeof(dst->sched_name));
+       strlcpy(dst->sched_name, sched_name, sizeof(dst->sched_name));
        dst->flags = src->flags;
        dst->timeout = src->timeout / HZ;
        dst->netmask = src->netmask;
@@ -2892,6 +2910,7 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
        struct ip_vs_flags flags = { .flags = svc->flags,
                                     .mask = ~0 };
        struct ip_vs_kstats kstats;
+       char *sched_name;
 
        nl_service = nla_nest_start(skb, IPVS_CMD_ATTR_SERVICE);
        if (!nl_service)
@@ -2910,8 +2929,9 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
        }
 
        sched = rcu_dereference_protected(svc->scheduler, 1);
+       sched_name = sched ? sched->name : "none";
        pe = rcu_dereference_protected(svc->pe, 1);
-       if (nla_put_string(skb, IPVS_SVC_ATTR_SCHED_NAME, sched->name) ||
+       if (nla_put_string(skb, IPVS_SVC_ATTR_SCHED_NAME, sched_name) ||
            (pe && nla_put_string(skb, IPVS_SVC_ATTR_PE_NAME, pe->name)) ||
            nla_put(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags) ||
            nla_put_u32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ) ||
index 199760c71f3995f88dbe73b159906cf7840cdded..7e814164794346daf6038e4b45cb5e1f8c762813 100644 (file)
@@ -74,7 +74,7 @@ void ip_vs_unbind_scheduler(struct ip_vs_service *svc,
 
        if (sched->done_service)
                sched->done_service(svc);
-       /* svc->scheduler can not be set to NULL */
+       /* svc->scheduler can be set to NULL only by caller */
 }
 
 
@@ -147,21 +147,21 @@ void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler)
 
 void ip_vs_scheduler_err(struct ip_vs_service *svc, const char *msg)
 {
-       struct ip_vs_scheduler *sched;
+       struct ip_vs_scheduler *sched = rcu_dereference(svc->scheduler);
+       char *sched_name = sched ? sched->name : "none";
 
-       sched = rcu_dereference(svc->scheduler);
        if (svc->fwmark) {
                IP_VS_ERR_RL("%s: FWM %u 0x%08X - %s\n",
-                            sched->name, svc->fwmark, svc->fwmark, msg);
+                            sched_name, svc->fwmark, svc->fwmark, msg);
 #ifdef CONFIG_IP_VS_IPV6
        } else if (svc->af == AF_INET6) {
                IP_VS_ERR_RL("%s: %s [%pI6c]:%d - %s\n",
-                            sched->name, ip_vs_proto_name(svc->protocol),
+                            sched_name, ip_vs_proto_name(svc->protocol),
                             &svc->addr.in6, ntohs(svc->port), msg);
 #endif
        } else {
                IP_VS_ERR_RL("%s: %s %pI4:%d - %s\n",
-                            sched->name, ip_vs_proto_name(svc->protocol),
+                            sched_name, ip_vs_proto_name(svc->protocol),
                             &svc->addr.ip, ntohs(svc->port), msg);
        }
 }
index b08ba9538d121bad95ab9aa579b2b37523f57dc2..d99ad93eb85508594cc5f6919a0b9eb005f19b33 100644 (file)
@@ -612,7 +612,7 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp,
                        pkts = atomic_add_return(1, &cp->in_pkts);
                else
                        pkts = sysctl_sync_threshold(ipvs);
-               ip_vs_sync_conn(net, cp->control, pkts);
+               ip_vs_sync_conn(net, cp, pkts);
        }
 }
 
index bf66a8657a5f7c7e1a2d3adbde3a05245c598249..258a0b0e82a293db38533a114c5c3a0bb2c03b9f 100644 (file)
@@ -130,7 +130,6 @@ static struct rtable *do_output_route4(struct net *net, __be32 daddr,
 
        memset(&fl4, 0, sizeof(fl4));
        fl4.daddr = daddr;
-       fl4.saddr = (rt_mode & IP_VS_RT_MODE_CONNECT) ? *saddr : 0;
        fl4.flowi4_flags = (rt_mode & IP_VS_RT_MODE_KNOWN_NH) ?
                           FLOWI_FLAG_KNOWN_NH : 0;
 
@@ -505,6 +504,13 @@ err_put:
        return -1;
 
 err_unreach:
+       /* The ip6_link_failure function requires the dev field to be set
+        * in order to get the net (further for the sake of fwmark
+        * reflection).
+        */
+       if (!skb->dev)
+               skb->dev = skb_dst(skb)->dev;
+
        dst_link_failure(skb);
        return -1;
 }
@@ -523,10 +529,27 @@ static inline int ip_vs_tunnel_xmit_prepare(struct sk_buff *skb,
        if (ret == NF_ACCEPT) {
                nf_reset(skb);
                skb_forward_csum(skb);
+               if (!skb->sk)
+                       skb_sender_cpu_clear(skb);
        }
        return ret;
 }
 
+/* In the event of a remote destination, it's possible that we would have
+ * matches against an old socket (particularly a TIME-WAIT socket). This
+ * causes havoc down the line (ip_local_out et. al. expect regular sockets
+ * and invalid memory accesses will happen) so simply drop the association
+ * in this case.
+*/
+static inline void ip_vs_drop_early_demux_sk(struct sk_buff *skb)
+{
+       /* If dev is set, the packet came from the LOCAL_IN callback and
+        * not from a local TCP socket.
+        */
+       if (skb->dev)
+               skb_orphan(skb);
+}
+
 /* return NF_STOLEN (sent) or NF_ACCEPT if local=1 (not sent) */
 static inline int ip_vs_nat_send_or_cont(int pf, struct sk_buff *skb,
                                         struct ip_vs_conn *cp, int local)
@@ -538,12 +561,23 @@ static inline int ip_vs_nat_send_or_cont(int pf, struct sk_buff *skb,
                ip_vs_notrack(skb);
        else
                ip_vs_update_conntrack(skb, cp, 1);
+
+       /* Remove the early_demux association unless it's bound for the
+        * exact same port and address on this host after translation.
+        */
+       if (!local || cp->vport != cp->dport ||
+           !ip_vs_addr_equal(cp->af, &cp->vaddr, &cp->daddr))
+               ip_vs_drop_early_demux_sk(skb);
+
        if (!local) {
                skb_forward_csum(skb);
+               if (!skb->sk)
+                       skb_sender_cpu_clear(skb);
                NF_HOOK(pf, NF_INET_LOCAL_OUT, NULL, skb,
                        NULL, skb_dst(skb)->dev, dst_output_sk);
        } else
                ret = NF_ACCEPT;
+
        return ret;
 }
 
@@ -557,7 +591,10 @@ static inline int ip_vs_send_or_cont(int pf, struct sk_buff *skb,
        if (likely(!(cp->flags & IP_VS_CONN_F_NFCT)))
                ip_vs_notrack(skb);
        if (!local) {
+               ip_vs_drop_early_demux_sk(skb);
                skb_forward_csum(skb);
+               if (!skb->sk)
+                       skb_sender_cpu_clear(skb);
                NF_HOOK(pf, NF_INET_LOCAL_OUT, NULL, skb,
                        NULL, skb_dst(skb)->dev, dst_output_sk);
        } else
@@ -845,6 +882,8 @@ ip_vs_prepare_tunneled_skb(struct sk_buff *skb, int skb_af,
        struct ipv6hdr *old_ipv6h = NULL;
 #endif
 
+       ip_vs_drop_early_demux_sk(skb);
+
        if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) {
                new_skb = skb_realloc_headroom(skb, max_headroom);
                if (!new_skb)
index 13fad8668f83d7ea4c7862b4c24d1234475ac37d..3c20d02aee738c5293a5b449f28ebff596c7232d 100644 (file)
@@ -287,6 +287,46 @@ static void nf_ct_del_from_dying_or_unconfirmed_list(struct nf_conn *ct)
        spin_unlock(&pcpu->lock);
 }
 
+/* Released via destroy_conntrack() */
+struct nf_conn *nf_ct_tmpl_alloc(struct net *net, u16 zone, gfp_t flags)
+{
+       struct nf_conn *tmpl;
+
+       tmpl = kzalloc(sizeof(*tmpl), flags);
+       if (tmpl == NULL)
+               return NULL;
+
+       tmpl->status = IPS_TEMPLATE;
+       write_pnet(&tmpl->ct_net, net);
+
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+       if (zone) {
+               struct nf_conntrack_zone *nf_ct_zone;
+
+               nf_ct_zone = nf_ct_ext_add(tmpl, NF_CT_EXT_ZONE, flags);
+               if (!nf_ct_zone)
+                       goto out_free;
+               nf_ct_zone->id = zone;
+       }
+#endif
+       atomic_set(&tmpl->ct_general.use, 0);
+
+       return tmpl;
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+out_free:
+       kfree(tmpl);
+       return NULL;
+#endif
+}
+EXPORT_SYMBOL_GPL(nf_ct_tmpl_alloc);
+
+static void nf_ct_tmpl_free(struct nf_conn *tmpl)
+{
+       nf_ct_ext_destroy(tmpl);
+       nf_ct_ext_free(tmpl);
+       kfree(tmpl);
+}
+
 static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
@@ -298,6 +338,10 @@ destroy_conntrack(struct nf_conntrack *nfct)
        NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
        NF_CT_ASSERT(!timer_pending(&ct->timeout));
 
+       if (unlikely(nf_ct_is_template(ct))) {
+               nf_ct_tmpl_free(ct);
+               return;
+       }
        rcu_read_lock();
        l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
        if (l4proto && l4proto->destroy)
@@ -540,28 +584,6 @@ out:
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert);
 
-/* deletion from this larval template list happens via nf_ct_put() */
-void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl)
-{
-       struct ct_pcpu *pcpu;
-
-       __set_bit(IPS_TEMPLATE_BIT, &tmpl->status);
-       __set_bit(IPS_CONFIRMED_BIT, &tmpl->status);
-       nf_conntrack_get(&tmpl->ct_general);
-
-       /* add this conntrack to the (per cpu) tmpl list */
-       local_bh_disable();
-       tmpl->cpu = smp_processor_id();
-       pcpu = per_cpu_ptr(nf_ct_net(tmpl)->ct.pcpu_lists, tmpl->cpu);
-
-       spin_lock(&pcpu->lock);
-       /* Overload tuple linked list to put us in template list. */
-       hlist_nulls_add_head_rcu(&tmpl->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
-                                &pcpu->tmpl);
-       spin_unlock_bh(&pcpu->lock);
-}
-EXPORT_SYMBOL_GPL(nf_conntrack_tmpl_insert);
-
 /* Confirm a connection given skb; places it in hash table */
 int
 __nf_conntrack_confirm(struct sk_buff *skb)
@@ -1522,10 +1544,8 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
        sz = nr_slots * sizeof(struct hlist_nulls_head);
        hash = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
                                        get_order(sz));
-       if (!hash) {
-               printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n");
+       if (!hash)
                hash = vzalloc(sz);
-       }
 
        if (hash && nulls)
                for (i = 0; i < nr_slots; i++)
@@ -1751,7 +1771,6 @@ int nf_conntrack_init_net(struct net *net)
                spin_lock_init(&pcpu->lock);
                INIT_HLIST_NULLS_HEAD(&pcpu->unconfirmed, UNCONFIRMED_NULLS_VAL);
                INIT_HLIST_NULLS_HEAD(&pcpu->dying, DYING_NULLS_VAL);
-               INIT_HLIST_NULLS_HEAD(&pcpu->tmpl, TEMPLATE_NULLS_VAL);
        }
 
        net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
index 7a17070c5dabb979c2cb90b7b62f35a79cdc92c0..b45a4223cb058a47ae2863a4166cd5085e587ca6 100644 (file)
@@ -219,7 +219,8 @@ static inline int expect_clash(const struct nf_conntrack_expect *a,
                        a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
        }
 
-       return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask);
+       return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask) &&
+              nf_ct_zone(a->master) == nf_ct_zone(b->master);
 }
 
 static inline int expect_matches(const struct nf_conntrack_expect *a,
index d1c23940a86ad96cddbf1aefe0747c43fddca920..6b8b0abbfab482280ae6a318f8bc58260e0b21c8 100644 (file)
@@ -2995,11 +2995,6 @@ ctnetlink_create_expect(struct net *net, u16 zone,
        }
 
        err = nf_ct_expect_related_report(exp, portid, report);
-       if (err < 0)
-               goto err_exp;
-
-       return 0;
-err_exp:
        nf_ct_expect_put(exp);
 err_ct:
        nf_ct_put(ct);
index 789feeae6c44a82b44e040ae2a6bec6f26cbe450..d7f1685279034b5e3b62748284d24c52cc1f8907 100644 (file)
@@ -349,23 +349,20 @@ static void __net_exit synproxy_proc_exit(struct net *net)
 static int __net_init synproxy_net_init(struct net *net)
 {
        struct synproxy_net *snet = synproxy_pernet(net);
-       struct nf_conntrack_tuple t;
        struct nf_conn *ct;
        int err = -ENOMEM;
 
-       memset(&t, 0, sizeof(t));
-       ct = nf_conntrack_alloc(net, 0, &t, &t, GFP_KERNEL);
-       if (IS_ERR(ct)) {
-               err = PTR_ERR(ct);
+       ct = nf_ct_tmpl_alloc(net, 0, GFP_KERNEL);
+       if (!ct)
                goto err1;
-       }
 
        if (!nfct_seqadj_ext_add(ct))
                goto err2;
        if (!nfct_synproxy_ext_add(ct))
                goto err2;
 
-       nf_conntrack_tmpl_insert(net, ct);
+       __set_bit(IPS_CONFIRMED_BIT, &ct->status);
+       nf_conntrack_get(&ct->ct_general);
        snet->tmpl = ct;
 
        snet->stats = alloc_percpu(struct synproxy_stats);
index 75747aecdebe6344ccbfcf178c299be013d8f763..43ddeee404e91f97908fb9228c1e873931b75bcc 100644 (file)
@@ -184,7 +184,6 @@ out:
 static int xt_ct_tg_check(const struct xt_tgchk_param *par,
                          struct xt_ct_target_info_v1 *info)
 {
-       struct nf_conntrack_tuple t;
        struct nf_conn *ct;
        int ret = -EOPNOTSUPP;
 
@@ -202,11 +201,11 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
        if (ret < 0)
                goto err1;
 
-       memset(&t, 0, sizeof(t));
-       ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
-       ret = PTR_ERR(ct);
-       if (IS_ERR(ct))
+       ct = nf_ct_tmpl_alloc(par->net, info->zone, GFP_KERNEL);
+       if (!ct) {
+               ret = -ENOMEM;
                goto err2;
+       }
 
        ret = 0;
        if ((info->ct_events || info->exp_events) &&
@@ -227,8 +226,8 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
                if (ret < 0)
                        goto err3;
        }
-
-       nf_conntrack_tmpl_insert(par->net, ct);
+       __set_bit(IPS_CONFIRMED_BIT, &ct->status);
+       nf_conntrack_get(&ct->ct_general);
 out:
        info->ct = ct;
        return 0;
index f407ebc13481ae5caa0f634db643d034c7af7e6a..29d2c31f406ca585d5f0eb1f08bcaf26d8364053 100644 (file)
@@ -126,6 +126,7 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
                goto out;
        }
 
+       sysfs_attr_init(&info->timer->attr.attr);
        info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL);
        if (!info->timer->attr.attr.name) {
                ret = -ENOMEM;
index 9a0ae7172f9271851f7a7c036e1c1980f45e5255..67d2104778636c62e7d3fa94c73ce5fb2cd4cb7d 100644 (file)
@@ -357,25 +357,52 @@ err1:
        return NULL;
 }
 
+
+static void
+__netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, bool tx_ring, void **pg_vec,
+                  unsigned int order)
+{
+       struct netlink_sock *nlk = nlk_sk(sk);
+       struct sk_buff_head *queue;
+       struct netlink_ring *ring;
+
+       queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
+       ring  = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
+
+       spin_lock_bh(&queue->lock);
+
+       ring->frame_max         = req->nm_frame_nr - 1;
+       ring->head              = 0;
+       ring->frame_size        = req->nm_frame_size;
+       ring->pg_vec_pages      = req->nm_block_size / PAGE_SIZE;
+
+       swap(ring->pg_vec_len, req->nm_block_nr);
+       swap(ring->pg_vec_order, order);
+       swap(ring->pg_vec, pg_vec);
+
+       __skb_queue_purge(queue);
+       spin_unlock_bh(&queue->lock);
+
+       WARN_ON(atomic_read(&nlk->mapped));
+
+       if (pg_vec)
+               free_pg_vec(pg_vec, order, req->nm_block_nr);
+}
+
 static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req,
-                           bool closing, bool tx_ring)
+                           bool tx_ring)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
        struct netlink_ring *ring;
-       struct sk_buff_head *queue;
        void **pg_vec = NULL;
        unsigned int order = 0;
-       int err;
 
        ring  = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
-       queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
 
-       if (!closing) {
-               if (atomic_read(&nlk->mapped))
-                       return -EBUSY;
-               if (atomic_read(&ring->pending))
-                       return -EBUSY;
-       }
+       if (atomic_read(&nlk->mapped))
+               return -EBUSY;
+       if (atomic_read(&ring->pending))
+               return -EBUSY;
 
        if (req->nm_block_nr) {
                if (ring->pg_vec != NULL)
@@ -407,31 +434,19 @@ static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req,
                        return -EINVAL;
        }
 
-       err = -EBUSY;
        mutex_lock(&nlk->pg_vec_lock);
-       if (closing || atomic_read(&nlk->mapped) == 0) {
-               err = 0;
-               spin_lock_bh(&queue->lock);
-
-               ring->frame_max         = req->nm_frame_nr - 1;
-               ring->head              = 0;
-               ring->frame_size        = req->nm_frame_size;
-               ring->pg_vec_pages      = req->nm_block_size / PAGE_SIZE;
-
-               swap(ring->pg_vec_len, req->nm_block_nr);
-               swap(ring->pg_vec_order, order);
-               swap(ring->pg_vec, pg_vec);
-
-               __skb_queue_purge(queue);
-               spin_unlock_bh(&queue->lock);
-
-               WARN_ON(atomic_read(&nlk->mapped));
+       if (atomic_read(&nlk->mapped) == 0) {
+               __netlink_set_ring(sk, req, tx_ring, pg_vec, order);
+               mutex_unlock(&nlk->pg_vec_lock);
+               return 0;
        }
+
        mutex_unlock(&nlk->pg_vec_lock);
 
        if (pg_vec)
                free_pg_vec(pg_vec, order, req->nm_block_nr);
-       return err;
+
+       return -EBUSY;
 }
 
 static void netlink_mm_open(struct vm_area_struct *vma)
@@ -900,10 +915,10 @@ static void netlink_sock_destruct(struct sock *sk)
 
                memset(&req, 0, sizeof(req));
                if (nlk->rx_ring.pg_vec)
-                       netlink_set_ring(sk, &req, true, false);
+                       __netlink_set_ring(sk, &req, false, NULL, 0);
                memset(&req, 0, sizeof(req));
                if (nlk->tx_ring.pg_vec)
-                       netlink_set_ring(sk, &req, true, true);
+                       __netlink_set_ring(sk, &req, true, NULL, 0);
        }
 #endif /* CONFIG_NETLINK_MMAP */
 
@@ -1081,6 +1096,11 @@ static int netlink_insert(struct sock *sk, u32 portid)
 
        err = __netlink_insert(table, sk);
        if (err) {
+               /* In case the hashtable backend returns with -EBUSY
+                * from here, it must not escape to the caller.
+                */
+               if (unlikely(err == -EBUSY))
+                       err = -EOVERFLOW;
                if (err == -EEXIST)
                        err = -EADDRINUSE;
                nlk_sk(sk)->portid = 0;
@@ -2223,7 +2243,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                        return -EINVAL;
                if (copy_from_user(&req, optval, sizeof(req)))
                        return -EFAULT;
-               err = netlink_set_ring(sk, &req, false,
+               err = netlink_set_ring(sk, &req,
                                       optname == NETLINK_TX_RING);
                break;
        }
index 8a8c0b8b4f63a4bd8e5ff776250189558e6fcb1e..ee34f474ad1465087da8fd506410559abe47d81e 100644 (file)
@@ -273,28 +273,36 @@ static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key,
        return 0;
 }
 
-static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
-                       __be32 *addr, __be32 new_addr)
+static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh,
+                                 __be32 addr, __be32 new_addr)
 {
        int transport_len = skb->len - skb_transport_offset(skb);
 
+       if (nh->frag_off & htons(IP_OFFSET))
+               return;
+
        if (nh->protocol == IPPROTO_TCP) {
                if (likely(transport_len >= sizeof(struct tcphdr)))
                        inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
-                                                *addr, new_addr, 1);
+                                                addr, new_addr, 1);
        } else if (nh->protocol == IPPROTO_UDP) {
                if (likely(transport_len >= sizeof(struct udphdr))) {
                        struct udphdr *uh = udp_hdr(skb);
 
                        if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
                                inet_proto_csum_replace4(&uh->check, skb,
-                                                        *addr, new_addr, 1);
+                                                        addr, new_addr, 1);
                                if (!uh->check)
                                        uh->check = CSUM_MANGLED_0;
                        }
                }
        }
+}
 
+static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
+                       __be32 *addr, __be32 new_addr)
+{
+       update_ip_l4_checksum(skb, nh, *addr, new_addr);
        csum_replace4(&nh->check, *addr, new_addr);
        skb_clear_hash(skb);
        *addr = new_addr;
index 4613df8c82900e32a4e0188688c9e0354022484d..65523948fb95e7cf7843efd447c7fc62b0c51b71 100644 (file)
@@ -752,7 +752,7 @@ int ovs_flow_init(void)
        BUILD_BUG_ON(sizeof(struct sw_flow_key) % sizeof(long));
 
        flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow)
-                                      + (num_possible_nodes()
+                                      + (nr_node_ids
                                          * sizeof(struct flow_stats *)),
                                       0, 0, NULL);
        if (flow_cache == NULL)
index c9e8741226c6d8785e89532aa09e029c3fd9e487..ed458b315ef4153233f65fa2af0bb0db55225bf8 100644 (file)
@@ -2403,7 +2403,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                }
                tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
                                          addr, hlen);
-               if (tp_len > dev->mtu + dev->hard_header_len) {
+               if (likely(tp_len >= 0) &&
+                   tp_len > dev->mtu + dev->hard_header_len) {
                        struct ethhdr *ehdr;
                        /* Earlier code assumed this would be a VLAN pkt,
                         * double-check this now that we have the actual
@@ -2784,7 +2785,7 @@ static int packet_release(struct socket *sock)
 static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto)
 {
        struct packet_sock *po = pkt_sk(sk);
-       const struct net_device *dev_curr;
+       struct net_device *dev_curr;
        __be16 proto_curr;
        bool need_rehook;
 
@@ -2808,15 +2809,13 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto)
 
                po->num = proto;
                po->prot_hook.type = proto;
-
-               if (po->prot_hook.dev)
-                       dev_put(po->prot_hook.dev);
-
                po->prot_hook.dev = dev;
 
                po->ifindex = dev ? dev->ifindex : 0;
                packet_cached_dev_assign(po, dev);
        }
+       if (dev_curr)
+               dev_put(dev_curr);
 
        if (proto == 0 || !need_rehook)
                goto out_unlock;
index 9a6b4f66187cf3e5ab533cd01344c9856834ebb7..140a44a5f7b7f1c08b3f329707b72fc75a9a81fe 100644 (file)
@@ -176,7 +176,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
 
        /* check for all kinds of wrapping and the like */
        start = (unsigned long)optval;
-       if (len < 0 || len + PAGE_SIZE - 1 < len || start + len < start) {
+       if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 || start + len < start) {
                ret = -EINVAL;
                goto out;
        }
index af427a3dbcba238103169ab2a58005feda5fa2f1..43ec92680ae8fe30d14496f5cf81a1baf53b49e3 100644 (file)
@@ -45,7 +45,7 @@ void tcf_hash_destroy(struct tc_action *a)
 }
 EXPORT_SYMBOL(tcf_hash_destroy);
 
-int tcf_hash_release(struct tc_action *a, int bind)
+int __tcf_hash_release(struct tc_action *a, bool bind, bool strict)
 {
        struct tcf_common *p = a->priv;
        int ret = 0;
@@ -53,7 +53,7 @@ int tcf_hash_release(struct tc_action *a, int bind)
        if (p) {
                if (bind)
                        p->tcfc_bindcnt--;
-               else if (p->tcfc_bindcnt > 0)
+               else if (strict && p->tcfc_bindcnt > 0)
                        return -EPERM;
 
                p->tcfc_refcnt--;
@@ -64,9 +64,10 @@ int tcf_hash_release(struct tc_action *a, int bind)
                        ret = 1;
                }
        }
+
        return ret;
 }
-EXPORT_SYMBOL(tcf_hash_release);
+EXPORT_SYMBOL(__tcf_hash_release);
 
 static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
                           struct tc_action *a)
@@ -136,7 +137,7 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a)
                head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];
                hlist_for_each_entry_safe(p, n, head, tcfc_head) {
                        a->priv = p;
-                       ret = tcf_hash_release(a, 0);
+                       ret = __tcf_hash_release(a, false, true);
                        if (ret == ACT_P_DELETED) {
                                module_put(a->ops->owner);
                                n_i++;
@@ -408,7 +409,7 @@ int tcf_action_destroy(struct list_head *actions, int bind)
        int ret = 0;
 
        list_for_each_entry_safe(a, tmp, actions, list) {
-               ret = tcf_hash_release(a, bind);
+               ret = __tcf_hash_release(a, bind, true);
                if (ret == ACT_P_DELETED)
                        module_put(a->ops->owner);
                else if (ret < 0)
index 1d56903fd4c79aa008c4c540aabd8b4c099e81a1..d0edeb7a1950b9a4c087f67344af0402aaa550e1 100644 (file)
 struct tcf_bpf_cfg {
        struct bpf_prog *filter;
        struct sock_filter *bpf_ops;
-       char *bpf_name;
+       const char *bpf_name;
        u32 bpf_fd;
        u16 bpf_num_ops;
+       bool is_ebpf;
 };
 
 static int tcf_bpf(struct sk_buff *skb, const struct tc_action *act,
@@ -207,6 +208,7 @@ static int tcf_bpf_init_from_ops(struct nlattr **tb, struct tcf_bpf_cfg *cfg)
        cfg->bpf_ops = bpf_ops;
        cfg->bpf_num_ops = bpf_num_ops;
        cfg->filter = fp;
+       cfg->is_ebpf = false;
 
        return 0;
 }
@@ -241,18 +243,40 @@ static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg)
        cfg->bpf_fd = bpf_fd;
        cfg->bpf_name = name;
        cfg->filter = fp;
+       cfg->is_ebpf = true;
 
        return 0;
 }
 
+static void tcf_bpf_cfg_cleanup(const struct tcf_bpf_cfg *cfg)
+{
+       if (cfg->is_ebpf)
+               bpf_prog_put(cfg->filter);
+       else
+               bpf_prog_destroy(cfg->filter);
+
+       kfree(cfg->bpf_ops);
+       kfree(cfg->bpf_name);
+}
+
+static void tcf_bpf_prog_fill_cfg(const struct tcf_bpf *prog,
+                                 struct tcf_bpf_cfg *cfg)
+{
+       cfg->is_ebpf = tcf_bpf_is_ebpf(prog);
+       cfg->filter = prog->filter;
+
+       cfg->bpf_ops = prog->bpf_ops;
+       cfg->bpf_name = prog->bpf_name;
+}
+
 static int tcf_bpf_init(struct net *net, struct nlattr *nla,
                        struct nlattr *est, struct tc_action *act,
                        int replace, int bind)
 {
        struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
+       struct tcf_bpf_cfg cfg, old;
        struct tc_act_bpf *parm;
        struct tcf_bpf *prog;
-       struct tcf_bpf_cfg cfg;
        bool is_bpf, is_ebpf;
        int ret;
 
@@ -301,6 +325,9 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
        prog = to_bpf(act);
        spin_lock_bh(&prog->tcf_lock);
 
+       if (ret != ACT_P_CREATED)
+               tcf_bpf_prog_fill_cfg(prog, &old);
+
        prog->bpf_ops = cfg.bpf_ops;
        prog->bpf_name = cfg.bpf_name;
 
@@ -316,29 +343,22 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
 
        if (ret == ACT_P_CREATED)
                tcf_hash_insert(act);
+       else
+               tcf_bpf_cfg_cleanup(&old);
 
        return ret;
 
 destroy_fp:
-       if (is_ebpf)
-               bpf_prog_put(cfg.filter);
-       else
-               bpf_prog_destroy(cfg.filter);
-
-       kfree(cfg.bpf_ops);
-       kfree(cfg.bpf_name);
-
+       tcf_bpf_cfg_cleanup(&cfg);
        return ret;
 }
 
 static void tcf_bpf_cleanup(struct tc_action *act, int bind)
 {
-       const struct tcf_bpf *prog = act->priv;
+       struct tcf_bpf_cfg tmp;
 
-       if (tcf_bpf_is_ebpf(prog))
-               bpf_prog_put(prog->filter);
-       else
-               bpf_prog_destroy(prog->filter);
+       tcf_bpf_prog_fill_cfg(act->priv, &tmp);
+       tcf_bpf_cfg_cleanup(&tmp);
 }
 
 static struct tc_action_ops act_bpf_ops __read_mostly = {
index a42a3b257226178eb5af04054a17813c04368613..268545050ddbd67245ead8394a82f44503657ea5 100644 (file)
@@ -98,6 +98,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                        return ret;
                ret = ACT_P_CREATED;
        } else {
+               if (bind)
+                       return 0;
                if (!ovr) {
                        tcf_hash_release(a, bind);
                        return -EEXIST;
index 17e6d6669c7fdf138915ac9549d3f06d9535d745..ff8b466a73f6c04510523843b800de6c0db4b093 100644 (file)
@@ -68,13 +68,12 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
                }
                ret = ACT_P_CREATED;
        } else {
-               p = to_pedit(a);
-               tcf_hash_release(a, bind);
                if (bind)
                        return 0;
+               tcf_hash_release(a, bind);
                if (!ovr)
                        return -EEXIST;
-
+               p = to_pedit(a);
                if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) {
                        keys = kmalloc(ksize, GFP_KERNEL);
                        if (keys == NULL)
index c79ecfd36e0f028388ea5f96a64dbb23451b01b1..e5168f8b9640964ce2dd95a896a24f6c986a959a 100644 (file)
@@ -378,7 +378,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
                goto errout;
 
        if (oldprog) {
-               list_replace_rcu(&prog->link, &oldprog->link);
+               list_replace_rcu(&oldprog->link, &prog->link);
                tcf_unbind_filter(tp, &oldprog->res);
                call_rcu(&oldprog->rcu, __cls_bpf_delete_prog);
        } else {
index 76bc3a20ffdb31bb4c9b51942de74c64928c2a3a..bb2a0f529c1f519f79f22ffa046013d7ac863eb5 100644 (file)
@@ -425,6 +425,8 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
        if (!fnew)
                goto err2;
 
+       tcf_exts_init(&fnew->exts, TCA_FLOW_ACT, TCA_FLOW_POLICE);
+
        fold = (struct flow_filter *)*arg;
        if (fold) {
                err = -EINVAL;
@@ -486,7 +488,6 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
                fnew->mask  = ~0U;
                fnew->tp = tp;
                get_random_bytes(&fnew->hashrnd, 4);
-               tcf_exts_init(&fnew->exts, TCA_FLOW_ACT, TCA_FLOW_POLICE);
        }
 
        fnew->perturb_timer.function = flow_perturbation;
@@ -526,7 +527,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
        if (*arg == 0)
                list_add_tail_rcu(&fnew->list, &head->filters);
        else
-               list_replace_rcu(&fnew->list, &fold->list);
+               list_replace_rcu(&fold->list, &fnew->list);
 
        *arg = (unsigned long)fnew;
 
index 9d37ccd95062a6840d1bb1e140b173dd1fe0b9d0..2f3d03f99487ed35c4af1e5c7ede590e4b0e3721 100644 (file)
@@ -499,7 +499,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
        *arg = (unsigned long) fnew;
 
        if (fold) {
-               list_replace_rcu(&fnew->list, &fold->list);
+               list_replace_rcu(&fold->list, &fnew->list);
                tcf_unbind_filter(tp, &fold->res);
                call_rcu(&fold->rcu, fl_destroy_filter);
        } else {
index 93d5742dc7e0f9730abd1726adf47857de1e64d4..6a783afe4960052912bf1241a22ab16d38d9e81a 100644 (file)
@@ -385,6 +385,19 @@ static void choke_reset(struct Qdisc *sch)
 {
        struct choke_sched_data *q = qdisc_priv(sch);
 
+       while (q->head != q->tail) {
+               struct sk_buff *skb = q->tab[q->head];
+
+               q->head = (q->head + 1) & q->tab_mask;
+               if (!skb)
+                       continue;
+               qdisc_qstats_backlog_dec(sch, skb);
+               --sch->q.qlen;
+               qdisc_drop(skb, sch);
+       }
+
+       memset(q->tab, 0, (q->tab_mask + 1) * sizeof(struct sk_buff *));
+       q->head = q->tail = 0;
        red_restart(&q->vars);
 }
 
index d75993f89facc0ce8d5df0d26aedcd016714a43e..a9ba030435a2a5c2ca4bea21d62c6d631c6168f4 100644 (file)
@@ -155,14 +155,23 @@ static unsigned int fq_codel_drop(struct Qdisc *sch)
        skb = dequeue_head(flow);
        len = qdisc_pkt_len(skb);
        q->backlogs[idx] -= len;
-       kfree_skb(skb);
        sch->q.qlen--;
        qdisc_qstats_drop(sch);
        qdisc_qstats_backlog_dec(sch, skb);
+       kfree_skb(skb);
        flow->dropped++;
        return idx;
 }
 
+static unsigned int fq_codel_qdisc_drop(struct Qdisc *sch)
+{
+       unsigned int prev_backlog;
+
+       prev_backlog = sch->qstats.backlog;
+       fq_codel_drop(sch);
+       return prev_backlog - sch->qstats.backlog;
+}
+
 static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct fq_codel_sched_data *q = qdisc_priv(sch);
@@ -279,10 +288,26 @@ begin:
 
 static void fq_codel_reset(struct Qdisc *sch)
 {
-       struct sk_buff *skb;
+       struct fq_codel_sched_data *q = qdisc_priv(sch);
+       int i;
 
-       while ((skb = fq_codel_dequeue(sch)) != NULL)
-               kfree_skb(skb);
+       INIT_LIST_HEAD(&q->new_flows);
+       INIT_LIST_HEAD(&q->old_flows);
+       for (i = 0; i < q->flows_cnt; i++) {
+               struct fq_codel_flow *flow = q->flows + i;
+
+               while (flow->head) {
+                       struct sk_buff *skb = dequeue_head(flow);
+
+                       qdisc_qstats_backlog_dec(sch, skb);
+                       kfree_skb(skb);
+               }
+
+               INIT_LIST_HEAD(&flow->flowchain);
+               codel_vars_init(&flow->cvars);
+       }
+       memset(q->backlogs, 0, q->flows_cnt * sizeof(u32));
+       sch->q.qlen = 0;
 }
 
 static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = {
@@ -604,7 +629,7 @@ static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
        .enqueue        =       fq_codel_enqueue,
        .dequeue        =       fq_codel_dequeue,
        .peek           =       qdisc_peek_dequeued,
-       .drop           =       fq_codel_drop,
+       .drop           =       fq_codel_qdisc_drop,
        .init           =       fq_codel_init,
        .reset          =       fq_codel_reset,
        .destroy        =       fq_codel_destroy,
index 89f8fcf73f18f6e091881cc829861285c0c8f8b7..ade9445a55abe468107f2bcb233e48da027afb4b 100644 (file)
@@ -216,6 +216,7 @@ static struct Qdisc_ops plug_qdisc_ops __read_mostly = {
        .peek        =       qdisc_peek_head,
        .init        =       plug_init,
        .change      =       plug_change,
+       .reset       =       qdisc_reset_queue,
        .owner       =       THIS_MODULE,
 };
 
index 7d14926633601b85c2d281d914fa978c8a038e10..52f75a5473e120f8d0a02a2ff1c0215ff02437b5 100644 (file)
@@ -306,10 +306,10 @@ drop:
                len = qdisc_pkt_len(skb);
                slot->backlog -= len;
                sfq_dec(q, x);
-               kfree_skb(skb);
                sch->q.qlen--;
                qdisc_qstats_drop(sch);
                qdisc_qstats_backlog_dec(sch, skb);
+               kfree_skb(skb);
                return len;
        }
 
index 1425ec2bbd5ae359a8e0408a89a6da6bb60bd87e..17bef01b9aa3e7f75328d39fc976f9e80d641e92 100644 (file)
@@ -2200,12 +2200,6 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
        if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen))
                return -EFAULT;
 
-       if (sctp_sk(sk)->subscribe.sctp_data_io_event)
-               pr_warn_ratelimited(DEPRECATED "%s (pid %d) "
-                                   "Requested SCTP_SNDRCVINFO event.\n"
-                                   "Use SCTP_RCVINFO through SCTP_RECVRCVINFO option instead.\n",
-                                   current->comm, task_pid_nr(current));
-
        /* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT,
         * if there is no data to be sent or retransmit, the stack will
         * immediately send up this notification.
index 9825ff0f91d6c0bde819105f639cae21883bbfad..6255d141133bb0ccabc195c8b4d9bce8cbe39c51 100644 (file)
@@ -240,8 +240,8 @@ static struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt, __be32 xid)
                req = xprt_alloc_bc_req(xprt, GFP_ATOMIC);
                if (!req)
                        goto not_found;
-               /* Note: this 'free' request adds it to xprt->bc_pa_list */
-               xprt_free_bc_request(req);
+               list_add_tail(&req->rq_bc_pa_list, &xprt->bc_pa_list);
+               xprt->bc_alloc_count++;
        }
        req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst,
                                rq_bc_pa_list);
@@ -336,7 +336,7 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
 
        spin_lock(&xprt->bc_pa_lock);
        list_del(&req->rq_bc_pa_list);
-       xprt->bc_alloc_count--;
+       xprt_dec_alloc_count(xprt, 1);
        spin_unlock(&xprt->bc_pa_lock);
 
        req->rq_private_buf.len = copied;
index cbc6af923dd1cb0baabc95161989133150269d4f..23608eb0ded2c94e363ed06e35384b08417e04ed 100644 (file)
@@ -1902,6 +1902,7 @@ call_transmit_status(struct rpc_task *task)
 
        switch (task->tk_status) {
        case -EAGAIN:
+       case -ENOBUFS:
                break;
        default:
                dprint_status(task);
@@ -1928,7 +1929,6 @@ call_transmit_status(struct rpc_task *task)
        case -ECONNABORTED:
        case -EADDRINUSE:
        case -ENOTCONN:
-       case -ENOBUFS:
        case -EPIPE:
                rpc_task_force_reencode(task);
        }
@@ -2057,12 +2057,13 @@ call_status(struct rpc_task *task)
        case -ECONNABORTED:
                rpc_force_rebind(clnt);
        case -EADDRINUSE:
-       case -ENOBUFS:
                rpc_delay(task, 3*HZ);
        case -EPIPE:
        case -ENOTCONN:
                task->tk_action = call_bind;
                break;
+       case -ENOBUFS:
+               rpc_delay(task, HZ>>2);
        case -EAGAIN:
                task->tk_action = call_transmit;
                break;
index e193c2b5476b3a83973e9799e2e826fdcd2b842c..0030376327b77f0a08d4af887286a0616a60069e 100644 (file)
@@ -527,6 +527,10 @@ static int xs_local_send_request(struct rpc_task *task)
                              true, &sent);
        dprintk("RPC:       %s(%u) = %d\n",
                        __func__, xdr->len - req->rq_bytes_sent, status);
+
+       if (status == -EAGAIN && sock_writeable(transport->inet))
+               status = -ENOBUFS;
+
        if (likely(sent > 0) || status == 0) {
                req->rq_bytes_sent += sent;
                req->rq_xmit_bytes_sent += sent;
@@ -539,6 +543,7 @@ static int xs_local_send_request(struct rpc_task *task)
 
        switch (status) {
        case -ENOBUFS:
+               break;
        case -EAGAIN:
                status = xs_nospace(task);
                break;
@@ -589,6 +594,9 @@ static int xs_udp_send_request(struct rpc_task *task)
        if (status == -EPERM)
                goto process_status;
 
+       if (status == -EAGAIN && sock_writeable(transport->inet))
+               status = -ENOBUFS;
+
        if (sent > 0 || status == 0) {
                req->rq_xmit_bytes_sent += sent;
                if (sent >= req->rq_slen)
@@ -669,9 +677,6 @@ static int xs_tcp_send_request(struct rpc_task *task)
                dprintk("RPC:       xs_tcp_send_request(%u) = %d\n",
                                xdr->len - req->rq_bytes_sent, status);
 
-               if (unlikely(sent == 0 && status < 0))
-                       break;
-
                /* If we've sent the entire packet, immediately
                 * reset the count of bytes sent. */
                req->rq_bytes_sent += sent;
@@ -681,18 +686,21 @@ static int xs_tcp_send_request(struct rpc_task *task)
                        return 0;
                }
 
-               if (sent != 0)
-                       continue;
-               status = -EAGAIN;
-               break;
+               if (status < 0)
+                       break;
+               if (sent == 0) {
+                       status = -EAGAIN;
+                       break;
+               }
        }
+       if (status == -EAGAIN && sk_stream_is_writeable(transport->inet))
+               status = -ENOBUFS;
 
        switch (status) {
        case -ENOTSOCK:
                status = -ENOTCONN;
                /* Should we call xs_close() here? */
                break;
-       case -ENOBUFS:
        case -EAGAIN:
                status = xs_nospace(task);
                break;
@@ -703,6 +711,7 @@ static int xs_tcp_send_request(struct rpc_task *task)
        case -ECONNREFUSED:
        case -ENOTCONN:
        case -EADDRINUSE:
+       case -ENOBUFS:
        case -EPIPE:
                clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
        }
index 915b328b9ac5e71afe3a979640288ad2bfab4a22..59cabc9bce693f5f39f1d2db8f436a18ac2efcaa 100644 (file)
@@ -797,23 +797,18 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
        return false;
 }
 
-bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
-                            struct cfg80211_chan_def *chandef,
-                            enum nl80211_iftype iftype)
+static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
+                                    struct cfg80211_chan_def *chandef,
+                                    enum nl80211_iftype iftype,
+                                    bool check_no_ir)
 {
        bool res;
        u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
                               IEEE80211_CHAN_RADAR;
 
-       trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
+       trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
 
-       /*
-        * Under certain conditions suggested by some regulatory bodies a
-        * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
-        * only if such relaxations are not enabled and the conditions are not
-        * met.
-        */
-       if (!cfg80211_ir_permissive_chan(wiphy, iftype, chandef->chan))
+       if (check_no_ir)
                prohibited_flags |= IEEE80211_CHAN_NO_IR;
 
        if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
@@ -827,8 +822,36 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
        trace_cfg80211_return_bool(res);
        return res;
 }
+
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+                            struct cfg80211_chan_def *chandef,
+                            enum nl80211_iftype iftype)
+{
+       return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
+}
 EXPORT_SYMBOL(cfg80211_reg_can_beacon);
 
+bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
+                                  struct cfg80211_chan_def *chandef,
+                                  enum nl80211_iftype iftype)
+{
+       bool check_no_ir;
+
+       ASSERT_RTNL();
+
+       /*
+        * Under certain conditions suggested by some regulatory bodies a
+        * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
+        * only if such relaxations are not enabled and the conditions are not
+        * met.
+        */
+       check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
+                                                  chandef->chan);
+
+       return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
+}
+EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
+
 int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
                                 struct cfg80211_chan_def *chandef)
 {
index c264effd00a69f97654e9a53959414321ea01668..76b41578a838e3bed8596c5950ffbd6881d54a64 100644 (file)
@@ -2003,7 +2003,8 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
        switch (iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
-               if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
+               if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
+                                                  iftype)) {
                        result = -EINVAL;
                        break;
                }
@@ -3403,8 +3404,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        } else if (!nl80211_get_ap_channel(rdev, &params))
                return -EINVAL;
 
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
-                                    wdev->iftype))
+       if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
+                                          wdev->iftype))
                return -EINVAL;
 
        if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
@@ -6492,8 +6493,8 @@ skip_beacons:
        if (err)
                return err;
 
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
-                                    wdev->iftype))
+       if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
+                                          wdev->iftype))
                return -EINVAL;
 
        err = cfg80211_chandef_dfs_required(wdev->wiphy,
@@ -10170,7 +10171,8 @@ static int nl80211_tdls_channel_switch(struct sk_buff *skb,
                return -EINVAL;
 
        /* we will be active on the TDLS link */
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, wdev->iftype))
+       if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
+                                          wdev->iftype))
                return -EINVAL;
 
        /* don't allow switching to DFS channels */
index d359e0610198c5c3d2094120e4ba3cf714d8dc21..aa2d75482017e1a258eb0cdb7271b2d615d8782e 100644 (file)
@@ -544,15 +544,15 @@ static int call_crda(const char *alpha2)
        reg_regdb_query(alpha2);
 
        if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) {
-               pr_info("Exceeded CRDA call max attempts. Not calling CRDA\n");
+               pr_debug("Exceeded CRDA call max attempts. Not calling CRDA\n");
                return -EINVAL;
        }
 
        if (!is_world_regdom((char *) alpha2))
-               pr_info("Calling CRDA for country: %c%c\n",
+               pr_debug("Calling CRDA for country: %c%c\n",
                        alpha2[0], alpha2[1]);
        else
-               pr_info("Calling CRDA to update world regulatory domain\n");
+               pr_debug("Calling CRDA to update world regulatory domain\n");
 
        return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
 }
@@ -1589,7 +1589,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
        case NL80211_IFTYPE_ADHOC:
-               return cfg80211_reg_can_beacon(wiphy, &chandef, iftype);
+               return cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
                return cfg80211_chandef_usable(wiphy, &chandef,
index af3617c9879e33f8be5c325ffdc3b5558e60b217..a808279a432a9ef1a23976ba169ac33ba377fe6d 100644 (file)
@@ -2358,20 +2358,23 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
 
 TRACE_EVENT(cfg80211_reg_can_beacon,
        TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
-                enum nl80211_iftype iftype),
-       TP_ARGS(wiphy, chandef, iftype),
+                enum nl80211_iftype iftype, bool check_no_ir),
+       TP_ARGS(wiphy, chandef, iftype, check_no_ir),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                CHAN_DEF_ENTRY
                __field(enum nl80211_iftype, iftype)
+               __field(bool, check_no_ir)
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
                CHAN_DEF_ASSIGN(chandef);
                __entry->iftype = iftype;
+               __entry->check_no_ir = check_no_ir;
        ),
-       TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
-                 WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
+       TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d check_no_ir=%s",
+                 WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype,
+                 BOOL_TO_STR(__entry->check_no_ir))
 );
 
 TRACE_EVENT(cfg80211_chandef_dfs_required,
index 8965d1bb881194685d1af344cbdfd2868c2aa9fd..125d6402f64f8555ec85b42f4c39e3af0f46ef3b 100644 (file)
  *
  *      For __dynamic_array(int, foo, bar) use __get_dynamic_array(foo)
  *            Use __get_dynamic_array_len(foo) to get the length of the array
- *            saved.
+ *            saved. Note, __get_dynamic_array_len() returns the total allocated
+ *            length of the dynamic array; __print_array() expects the second
+ *            parameter to be the number of elements. To get that, the array length
+ *            needs to be divided by the element size.
  *
  *      For __string(foo, bar) use __get_str(foo)
  *
@@ -288,7 +291,7 @@ TRACE_EVENT(foo_bar,
  *    This prints out the array that is defined by __array in a nice format.
  */
                  __print_array(__get_dynamic_array(list),
-                               __get_dynamic_array_len(list),
+                               __get_dynamic_array_len(list) / sizeof(int),
                                sizeof(int)),
                  __get_str(str), __get_bitmask(cpus))
 );
index 9cb8522d8d22a826caaec968e82c77516339ca01..f3d3fb42b8735e76aa54bd4c433574f7afc43b0e 100755 (executable)
@@ -137,7 +137,7 @@ my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
 my $kconfig = $ARGV[1];
 my $lsmod_file = $ENV{'LSMOD'};
 
-my @makefiles = `find $ksource -name Makefile 2>/dev/null`;
+my @makefiles = `find $ksource -name Makefile -or -name Kbuild 2>/dev/null`;
 chomp @makefiles;
 
 my %depends;
index e72548b5897ec237dd7463374871538c81a84fd7..d33437007ad229313a5ef483826e427a74350876 100644 (file)
@@ -1181,9 +1181,11 @@ void __key_link_end(struct key *keyring,
        if (index_key->type == &key_type_keyring)
                up_write(&keyring_serialise_link_sem);
 
-       if (edit && !edit->dead_leaf) {
-               key_payload_reserve(keyring,
-                                   keyring->datalen - KEYQUOTA_LINK_BYTES);
+       if (edit) {
+               if (!edit->dead_leaf) {
+                       key_payload_reserve(keyring,
+                               keyring->datalen - KEYQUOTA_LINK_BYTES);
+               }
                assoc_array_cancel_edit(edit);
        }
        up_write(&keyring->sem);
index 9ed32502470e9bc1d776d5d925ee48be587baa17..5ebb8968793670d6a23ee6e6d2b30df6243a63ca 100644 (file)
@@ -406,6 +406,7 @@ static __init int yama_init(void)
         */
        if (!security_module_enable("yama"))
                return 0;
+       yama_add_hooks();
 #endif
        pr_info("Yama: becoming mindful.\n");
 
index d126c03361aef87fb1239df1e42f547c5ce36aa9..75888dd38a7fc87acf5fcd7789570ad353dce482 100644 (file)
@@ -85,7 +85,7 @@ static DECLARE_RWSEM(snd_pcm_link_rwsem);
 void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
 {
        if (substream->pcm->nonatomic) {
-               down_read(&snd_pcm_link_rwsem);
+               down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING);
                mutex_lock(&substream->self_group.mutex);
        } else {
                read_lock(&snd_pcm_link_rwlock);
index 7bb988fa6b6d17764e08f39ecbf45f31ee2ff2ee..2a153d260836704011b6eadddfbc9b463e1b37b3 100644 (file)
@@ -740,8 +740,9 @@ static int handle_in_packet(struct amdtp_stream *s,
            s->data_block_counter != UINT_MAX)
                data_block_counter = s->data_block_counter;
 
-       if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) && data_block_counter == 0) ||
-           (s->data_block_counter == UINT_MAX)) {
+       if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) &&
+            data_block_counter == s->tx_first_dbc) ||
+           s->data_block_counter == UINT_MAX) {
                lost = false;
        } else if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
                lost = data_block_counter != s->data_block_counter;
index 26b909329e54d96d7fcb075f9538599aaf30cb09..b2cf9e75693b643ce0ac81ebdef15458fd2d4018 100644 (file)
@@ -157,6 +157,8 @@ struct amdtp_stream {
 
        /* quirk: fixed interval of dbc between previos/current packets. */
        unsigned int tx_dbc_interval;
+       /* quirk: indicate the value of dbc field in a first packet. */
+       unsigned int tx_first_dbc;
 
        bool callbacked;
        wait_queue_head_t callback_wait;
index 2682e7e3e5c98511e8bd26fddf452427f1e83a6a..c94a432f7cc653dca45316ea67bdc481b9e8e887 100644 (file)
@@ -248,8 +248,16 @@ efw_probe(struct fw_unit *unit,
        err = get_hardware_info(efw);
        if (err < 0)
                goto error;
+       /* AudioFire8 (since 2009) and AudioFirePre8 */
        if (entry->model_id == MODEL_ECHO_AUDIOFIRE_9)
                efw->is_af9 = true;
+       /* These models uses the same firmware. */
+       if (entry->model_id == MODEL_ECHO_AUDIOFIRE_2 ||
+           entry->model_id == MODEL_ECHO_AUDIOFIRE_4 ||
+           entry->model_id == MODEL_ECHO_AUDIOFIRE_9 ||
+           entry->model_id == MODEL_GIBSON_RIP ||
+           entry->model_id == MODEL_GIBSON_GOLDTOP)
+               efw->is_fireworks3 = true;
 
        snd_efw_proc_init(efw);
 
index 4f0201a95222a2502ec438199fe9e78cad33b647..084d414b228cf425dc99440cc081d65459bbe175 100644 (file)
@@ -71,6 +71,7 @@ struct snd_efw {
 
        /* for quirks */
        bool is_af9;
+       bool is_fireworks3;
        u32 firmware_version;
 
        unsigned int midi_in_ports;
index c55db1bddc80a0ceab4997279643f73840943cef..7e353f1f7bff359ea8845630aeff2521759e508f 100644 (file)
@@ -172,6 +172,15 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw)
        efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT;
        /* Fireworks reset dbc at bus reset. */
        efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK;
+       /*
+        * But Recent firmwares starts packets with non-zero dbc.
+        * Driver version 5.7.6 installs firmware version 5.7.3.
+        */
+       if (efw->is_fireworks3 &&
+           (efw->firmware_version == 0x5070000 ||
+            efw->firmware_version == 0x5070300 ||
+            efw->firmware_version == 0x5080000))
+               efw->tx_stream.tx_first_dbc = 0x02;
        /* AudioFire9 always reports wrong dbs. */
        if (efw->is_af9)
                efw->tx_stream.flags |= CIP_WRONG_DBS;
index b2da19b60f4e25cf6ec858832d6f33349313ca66..358f16195483f6b51c3a84a3cff672d8696951a6 100644 (file)
@@ -44,16 +44,10 @@ int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus)
 
        offset = snd_hdac_chip_readl(bus, LLCH);
 
-       if (offset < 0)
-               return -EIO;
-
        /* Lets walk the linked capabilities list */
        do {
                cur_cap = _snd_hdac_chip_read(l, bus, offset);
 
-               if (cur_cap < 0)
-                       return -EIO;
-
                dev_dbg(bus->dev, "Capability version: 0x%x\n",
                                ((cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF));
 
index f8ffbdbb450d785e281bd7a0aae3c6d8a8c2a2ab..3de47dd1a76d856f95c2051b1bde6e55522f2b55 100644 (file)
@@ -299,7 +299,7 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
                if (stream->direction != substream->stream)
                        continue;
 
-               if (stream->opened) {
+               if (!stream->opened) {
                        if (!hstream->decoupled)
                                snd_hdac_ext_stream_decouple(ebus, hstream, true);
                        res = hstream;
index 442500e06b7c7b66be05ec254a68e58d009089fe..5676b849379d43468267e8d12fc7367096a2ae4c 100644 (file)
@@ -56,8 +56,11 @@ int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
                enable ? "enable" : "disable");
 
        if (enable) {
-               if (!bus->i915_power_refcount++)
+               if (!bus->i915_power_refcount++) {
                        acomp->ops->get_power(acomp->dev);
+                       snd_hdac_set_codec_wakeup(bus, true);
+                       snd_hdac_set_codec_wakeup(bus, false);
+               }
        } else {
                WARN_ON(!bus->i915_power_refcount);
                if (!--bus->i915_power_refcount)
index 745535d1840a6713e802aaa8c1d475733b88720e..c38c68f579381d657786945baa3ab99b3ccae787 100644 (file)
@@ -867,7 +867,7 @@ static int azx_suspend(struct device *dev)
 
        chip = card->private_data;
        hda = container_of(chip, struct hda_intel, chip);
-       if (chip->disabled || hda->init_failed)
+       if (chip->disabled || hda->init_failed || !chip->running)
                return 0;
 
        bus = azx_bus(chip);
@@ -902,7 +902,7 @@ static int azx_resume(struct device *dev)
 
        chip = card->private_data;
        hda = container_of(chip, struct hda_intel, chip);
-       if (chip->disabled || hda->init_failed)
+       if (chip->disabled || hda->init_failed || !chip->running)
                return 0;
 
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
@@ -979,14 +979,16 @@ static int azx_runtime_resume(struct device *dev)
        if (!azx_has_pm_runtime(chip))
                return 0;
 
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
-               && hda->need_i915_power) {
-               bus =  azx_bus(chip);
-               snd_hdac_display_power(bus, true);
-               haswell_set_bclk(hda);
-               /* toggle codec wakeup bit for STATESTS read */
-               snd_hdac_set_codec_wakeup(bus, true);
-               snd_hdac_set_codec_wakeup(bus, false);
+       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+               bus = azx_bus(chip);
+               if (hda->need_i915_power) {
+                       snd_hdac_display_power(bus, true);
+                       haswell_set_bclk(hda);
+               } else {
+                       /* toggle codec wakeup bit for STATESTS read */
+                       snd_hdac_set_codec_wakeup(bus, true);
+                       snd_hdac_set_codec_wakeup(bus, false);
+               }
        }
 
        /* Read STATESTS before controller reset */
@@ -1025,7 +1027,7 @@ static int azx_runtime_idle(struct device *dev)
                return 0;
 
        if (!power_save_controller || !azx_has_pm_runtime(chip) ||
-           azx_bus(chip)->codec_powered)
+           azx_bus(chip)->codec_powered || !chip->running)
                return -EBUSY;
 
        return 0;
@@ -2182,6 +2184,8 @@ static const struct pci_device_id azx_ids[] = {
        /* ATI HDMI */
        { PCI_DEVICE(0x1002, 0x1308),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0x157a),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0x793b),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
        { PCI_DEVICE(0x1002, 0x7919),
@@ -2236,8 +2240,14 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0xaab0),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaac0),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0xaac8),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaad8),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaae8),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        /* VIA VT8251/VT8237A */
        { PCI_DEVICE(0x1106, 0x3288),
          .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
index 25ccf781fbe705cb5b2980814f7d4f90aff2d4a6..584a0343ab0cc132b7c2038679923b6617926cf7 100644 (file)
@@ -999,9 +999,7 @@ static void cs4210_spdif_automute(struct hda_codec *codec,
 
        spec->spdif_present = spdif_present;
        /* SPDIF TX on/off */
-       if (spdif_present)
-               snd_hda_set_pin_ctl(codec, spdif_pin,
-                                   spdif_present ? PIN_OUT : 0);
+       snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0);
 
        cs_automute(codec);
 }
index 95158914cc6ce0c8761c04fde20f81a4e21e1931..a97db5fc8a151aa43c0c99edc6ccf7efc0eaa52a 100644 (file)
@@ -3512,6 +3512,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x10de0070, .name = "GPU 70 HDMI/DP",  .patch = patch_nvhdmi },
 { .id = 0x10de0071, .name = "GPU 71 HDMI/DP",  .patch = patch_nvhdmi },
 { .id = 0x10de0072, .name = "GPU 72 HDMI/DP",  .patch = patch_nvhdmi },
+{ .id = 0x10de007d, .name = "GPU 7d HDMI/DP",  .patch = patch_nvhdmi },
 { .id = 0x10de8001, .name = "MCP73 HDMI",      .patch = patch_nvhdmi_2ch },
 { .id = 0x11069f80, .name = "VX900 HDMI/DP",   .patch = patch_via_hdmi },
 { .id = 0x11069f81, .name = "VX900 HDMI/DP",   .patch = patch_via_hdmi },
@@ -3576,6 +3577,7 @@ MODULE_ALIAS("snd-hda-codec-id:10de0067");
 MODULE_ALIAS("snd-hda-codec-id:10de0070");
 MODULE_ALIAS("snd-hda-codec-id:10de0071");
 MODULE_ALIAS("snd-hda-codec-id:10de0072");
+MODULE_ALIAS("snd-hda-codec-id:10de007d");
 MODULE_ALIAS("snd-hda-codec-id:10de8001");
 MODULE_ALIAS("snd-hda-codec-id:11069f80");
 MODULE_ALIAS("snd-hda-codec-id:11069f81");
index d35cf506a7dbc386a5aa003251d274ab9a305797..0b9847affbeccbc4b1a807b642120a3feaa397d0 100644 (file)
@@ -2222,7 +2222,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
        SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
        SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
-       SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
 
        SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
        SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
@@ -5061,7 +5061,7 @@ static const struct hda_fixup alc269_fixups[] = {
                        { 0x14, 0x90170110 },
                        { 0x17, 0x40000008 },
                        { 0x18, 0x411111f0 },
-                       { 0x19, 0x411111f0 },
+                       { 0x19, 0x01a1913c },
                        { 0x1a, 0x411111f0 },
                        { 0x1b, 0x411111f0 },
                        { 0x1d, 0x40f89b2d },
@@ -5185,9 +5185,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0665, "Dell XPS 13", ALC288_FIXUP_DELL_XPS_13),
+       SND_PCI_QUIRK(0x1028, 0x069a, "Dell Vostro 5480", ALC290_FIXUP_SUBWOOFER_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5398,8 +5400,6 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {0x19, 0x411111f0}, \
        {0x1a, 0x411111f0}, \
        {0x1b, 0x411111f0}, \
-       {0x1d, 0x40700001}, \
-       {0x1e, 0x411111f0}, \
        {0x21, 0x02211020}
 
 #define ALC282_STANDARD_PINS \
@@ -5430,8 +5430,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {0x15, 0x0221401f}, \
        {0x1a, 0x411111f0}, \
        {0x1b, 0x411111f0}, \
-       {0x1d, 0x40700001}, \
-       {0x1e, 0x411111f0}
+       {0x1d, 0x40700001}
 
 #define ALC298_STANDARD_PINS \
        {0x18, 0x411111f0}, \
@@ -5462,6 +5461,39 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x17, 0x40000000},
                {0x1d, 0x40700001},
                {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x40000000},
+               {0x14, 0x90170130},
+               {0x17, 0x411111f0},
+               {0x18, 0x411111f0},
+               {0x19, 0x411111f0},
+               {0x1a, 0x411111f0},
+               {0x1b, 0x01014020},
+               {0x1d, 0x4054c029},
+               {0x1e, 0x411111f0},
+               {0x21, 0x0221103f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x40000000},
+               {0x14, 0x90170150},
+               {0x17, 0x411111f0},
+               {0x18, 0x411111f0},
+               {0x19, 0x411111f0},
+               {0x1a, 0x411111f0},
+               {0x1b, 0x02011020},
+               {0x1d, 0x4054c029},
+               {0x1e, 0x411111f0},
+               {0x21, 0x0221105f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x40000000},
+               {0x14, 0x90170110},
+               {0x17, 0x411111f0},
+               {0x18, 0x411111f0},
+               {0x19, 0x411111f0},
+               {0x1a, 0x411111f0},
+               {0x1b, 0x01014020},
+               {0x1d, 0x4054c029},
+               {0x1e, 0x411111f0},
+               {0x21, 0x0221101f}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                {0x12, 0x90a60160},
                {0x14, 0x90170120},
@@ -5524,10 +5556,19 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x21, 0x02211030}),
        SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC256_STANDARD_PINS,
-               {0x13, 0x40000000}),
+               {0x13, 0x40000000},
+               {0x1d, 0x40700001},
+               {0x1e, 0x411111f0}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC256_STANDARD_PINS,
+               {0x13, 0x411111f0},
+               {0x1d, 0x40700001},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC256_STANDARD_PINS,
-               {0x13, 0x411111f0}),
+               {0x13, 0x411111f0},
+               {0x1d, 0x4077992d},
+               {0x1e, 0x411111ff}),
        SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
                {0x12, 0x90a60130},
                {0x13, 0x40000000},
@@ -5690,35 +5731,48 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x13, 0x411111f0},
                {0x16, 0x01014020},
                {0x18, 0x411111f0},
-               {0x19, 0x01a19030}),
+               {0x19, 0x01a19030},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
                ALC292_STANDARD_PINS,
                {0x12, 0x90a60140},
                {0x13, 0x411111f0},
                {0x16, 0x01014020},
                {0x18, 0x02a19031},
-               {0x19, 0x01a1903e}),
+               {0x19, 0x01a1903e},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
                ALC292_STANDARD_PINS,
                {0x12, 0x90a60140},
                {0x13, 0x411111f0},
                {0x16, 0x411111f0},
                {0x18, 0x411111f0},
-               {0x19, 0x411111f0}),
+               {0x19, 0x411111f0},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC292_STANDARD_PINS,
                {0x12, 0x40000000},
                {0x13, 0x90a60140},
                {0x16, 0x21014020},
                {0x18, 0x411111f0},
-               {0x19, 0x21a19030}),
+               {0x19, 0x21a19030},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC292_STANDARD_PINS,
                {0x12, 0x40000000},
                {0x13, 0x90a60140},
                {0x16, 0x411111f0},
                {0x18, 0x411111f0},
-               {0x19, 0x411111f0}),
+               {0x19, 0x411111f0},
+               {0x1e, 0x411111f0}),
+       SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
+               {0x12, 0x40000000},
+               {0x13, 0x90a60140},
+               {0x16, 0x21014020},
+               {0x18, 0x411111f0},
+               {0x19, 0x21a19030},
+               {0x1e, 0x411111ff}),
        SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC298_STANDARD_PINS,
                {0x12, 0x90a60130},
index dcc7fe91244c2dfada5c97fbb42df06dbd857bbf..9d947aef2c8b60b99f63fd9464ad289bef0c7061 100644 (file)
@@ -2920,7 +2920,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x148a,
                      "HP Mini", STAC_92HD83XXX_HP_LED),
        SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD83XXX_HP),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_TOSHIBA, 0xfa91,
+       /* match both for 0xfa91 and 0xfa93 */
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_TOSHIBA, 0xfffd, 0xfa91,
                      "Toshiba Satellite S50D", STAC_92HD83XXX_GPIO10_EAPD),
        {} /* terminator */
 };
index 6492bca8c70f8bbfdf31e2fb13321904f5a5b00a..4ca12665ff730c6980e2a4366dd195e47f94aecd 100644 (file)
@@ -88,7 +88,7 @@ static int dac_mute_put(struct snd_kcontrol *ctl,
        int changed;
 
        mutex_lock(&chip->mutex);
-       changed = !value->value.integer.value[0] != chip->dac_mute;
+       changed = (!value->value.integer.value[0]) != chip->dac_mute;
        if (changed) {
                chip->dac_mute = !value->value.integer.value[0];
                chip->model.update_dac_mute(chip);
index d7ec4756e45bf9bab0c08059ee74c39b4ea3c812..8e36198474d94d59cd8b7bda10e6be434103fa55 100644 (file)
@@ -457,14 +457,14 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
        case SND_SOC_DAIFMT_RIGHT_J:
                if (params_width(params) == 16) {
                        snd_soc_update_bits(codec, CS4265_DAC_CTL,
-                               CS4265_DAC_CTL_DIF, (1 << 5));
+                               CS4265_DAC_CTL_DIF, (2 << 4));
                        snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
-                               CS4265_SPDIF_CTL2_DIF, (1 << 7));
+                               CS4265_SPDIF_CTL2_DIF, (2 << 6));
                } else {
                        snd_soc_update_bits(codec, CS4265_DAC_CTL,
-                               CS4265_DAC_CTL_DIF, (3 << 5));
+                               CS4265_DAC_CTL_DIF, (3 << 4));
                        snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
-                               CS4265_SPDIF_CTL2_DIF, (1 << 7));
+                               CS4265_SPDIF_CTL2_DIF, (3 << 6));
                }
                break;
        case SND_SOC_DAIFMT_LEFT_J:
@@ -473,7 +473,7 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
                snd_soc_update_bits(codec, CS4265_ADC_CTL,
                        CS4265_ADC_DIF, 0);
                snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
-                       CS4265_SPDIF_CTL2_DIF, (1 << 6));
+                       CS4265_SPDIF_CTL2_DIF, 0);
 
                break;
        default:
index 477e13d309713e56a5a4416d054350185fea0007..e7ba557979cb2589439234d6bd0ddbbdc38985e5 100644 (file)
@@ -102,7 +102,7 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec)
 
        if (val != -1) {
                regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
-                                       PCM1681_DEEMPH_RATE_MASK, val);
+                                  PCM1681_DEEMPH_RATE_MASK, val << 3);
                enable = 1;
        } else
                enable = 0;
index 9ce311e088fc514bf8cde70dd120a3074f78bfe5..961bd7e5877ee42c3e50f7a3e2e826a1ffab9cc8 100644 (file)
@@ -2943,6 +2943,9 @@ static int rt5645_irq_detection(struct rt5645_priv *rt5645)
 {
        int val, btn_type, gpio_state = 0, report = 0;
 
+       if (!rt5645->codec)
+               return -EINVAL;
+
        switch (rt5645->pdata.jd_mode) {
        case 0: /* Not using rt5645 JD */
                if (rt5645->gpiod_hp_det) {
@@ -3338,6 +3341,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                break;
 
        case RT5645_DMIC_DATA_GPIO5:
+               regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+                       RT5645_I2S2_DAC_PIN_MASK, RT5645_I2S2_DAC_PIN_GPIO);
                regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
                        RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5);
                regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
index 0353a6a273ab4ca2bd5136c28aaedee14c6e54b2..278bb9f464c4120b681c7ad5c6086df89d6de3ab 100644 (file)
 #define RT5645_GP6_PIN_SFT                     6
 #define RT5645_GP6_PIN_GPIO6                   (0x0 << 6)
 #define RT5645_GP6_PIN_DMIC2_SDA               (0x1 << 6)
+#define RT5645_I2S2_DAC_PIN_MASK               (0x1 << 4)
+#define RT5645_I2S2_DAC_PIN_SFT                        4
+#define RT5645_I2S2_DAC_PIN_I2S                        (0x0 << 4)
+#define RT5645_I2S2_DAC_PIN_GPIO               (0x1 << 4)
 #define RT5645_GP8_PIN_MASK                    (0x1 << 3)
 #define RT5645_GP8_PIN_SFT                     3
 #define RT5645_GP8_PIN_GPIO8                   (0x0 << 3)
index bd7a344bf8c517edf69af2fda9e06e08488e47e0..1c317de2617623438bd169d9ba7cb89623139794 100644 (file)
 #define SGTL5000_BIAS_CTRL_MASK                        0x000e
 #define SGTL5000_BIAS_CTRL_SHIFT               1
 #define SGTL5000_BIAS_CTRL_WIDTH               3
-#define SGTL5000_SMALL_POP                     0
+#define SGTL5000_SMALL_POP                     1
 
 /*
  * SGTL5000_CHIP_MIC_CTRL
index 938d2cb6d78bee03e809f02462b17f951f0c953a..84a4f5ad80645f2f45079ea35fe8ce19da901f09 100644 (file)
@@ -315,7 +315,13 @@ static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        if (invert_fclk)
                ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
 
-       return regmap_write(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, ctrl1);
+       return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
+                       SSM4567_SAI_CTRL_1_BCLK |
+                       SSM4567_SAI_CTRL_1_FSYNC |
+                       SSM4567_SAI_CTRL_1_LJ |
+                       SSM4567_SAI_CTRL_1_TDM |
+                       SSM4567_SAI_CTRL_1_PDM,
+                       ctrl1);
 }
 
 static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
index c7647e066cfd76b07f6b1acd4d2a68ac04bae3bc..c0b940e2019f55f34bb53673a99a4594d7409ef3 100644 (file)
@@ -633,7 +633,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
                sub *= 100000;
                do_div(sub, freq);
 
-               if (sub < savesub) {
+               if (sub < savesub && !(i == 0 && psr == 0 && div2 == 0)) {
                        baudrate = tmprate;
                        savesub = sub;
                        pm = i;
index 3853ec2ddbc758d2c558dfcbe093d2cee59af8a1..6de5d5cd3280a92bf9d1b0ab71a5171e82a5bb0b 100644 (file)
@@ -7,4 +7,4 @@ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/
 obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/
 
 # Machine support
-obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/
+obj-$(CONFIG_SND_SOC) += boards/
index 620da1d1b9e3ea4fbde293c3e98fae4c30708ac1..0e0e4d9c021ff29bdf1f19eda2827ac459e4046c 100644 (file)
 #define MIN_FRAGMENT_SIZE (50 * 1024)
 #define MAX_FRAGMENT_SIZE (1024 * 1024)
 #define SST_GET_BYTES_PER_SAMPLE(pcm_wd_sz)  (((pcm_wd_sz + 15) >> 4) << 1)
+#ifdef CONFIG_PM
+#define GET_USAGE_COUNT(dev) (atomic_read(&dev->power.usage_count))
+#else
+#define GET_USAGE_COUNT(dev) 1
+#endif
 
 int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id)
 {
@@ -141,15 +146,9 @@ static int sst_power_control(struct device *dev, bool state)
        int ret = 0;
        int usage_count = 0;
 
-#ifdef CONFIG_PM
-       usage_count = atomic_read(&dev->power.usage_count);
-#else
-       usage_count = 1;
-#endif
-
        if (state == true) {
                ret = pm_runtime_get_sync(dev);
-
+               usage_count = GET_USAGE_COUNT(dev);
                dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count);
                if (ret < 0) {
                        dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret);
@@ -164,6 +163,7 @@ static int sst_power_control(struct device *dev, bool state)
                        }
                }
        } else {
+               usage_count = GET_USAGE_COUNT(dev);
                dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count);
                return sst_pm_runtime_put(ctx);
        }
index 4c01bb43928d136c93963730f1149f9d9bf4a66b..5bbaa667bec1c608c35968c983eaeece020ad8db 100644 (file)
@@ -701,6 +701,8 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
        if (byt == NULL)
                return -ENOMEM;
 
+       byt->dev = dev;
+
        ipc = &byt->ipc;
        ipc->dev = dev;
        ipc->ops.tx_msg = byt_tx_msg;
index d604ee80eda4be715601db603181e0291cc98747..70f832114a5aeffeeb7b0cc555f8f1b91bc40665 100644 (file)
@@ -69,12 +69,12 @@ static const struct snd_soc_dapm_route cht_audio_map[] = {
        {"Headphone", NULL, "HPR"},
        {"Ext Spk", NULL, "SPKL"},
        {"Ext Spk", NULL, "SPKR"},
-       {"AIF1 Playback", NULL, "ssp2 Tx"},
+       {"HiFi Playback", NULL, "ssp2 Tx"},
        {"ssp2 Tx", NULL, "codec_out0"},
        {"ssp2 Tx", NULL, "codec_out1"},
        {"codec_in0", NULL, "ssp2 Rx" },
        {"codec_in1", NULL, "ssp2 Rx" },
-       {"ssp2 Rx", NULL, "AIF1 Capture"},
+       {"ssp2 Rx", NULL, "HiFi Capture"},
 };
 
 static const struct snd_kcontrol_new cht_mc_controls[] = {
index f95f271aab0ce30412954428b426af2461438dea..f6efa9d4acadd5e056ea0a0494ed51da859fbc3a 100644 (file)
@@ -2119,6 +2119,8 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
        if (hsw == NULL)
                return -ENOMEM;
 
+       hsw->dev = dev;
+
        ipc = &hsw->ipc;
        ipc->dev = dev;
        ipc->ops.tx_msg = hsw_tx_msg;
index 4d44b5803e55206c02006b9359449df377477b6c..2d2536af141fc9157b2ecb402a969af6c808faf6 100644 (file)
@@ -103,7 +103,6 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = {
                .name = "MAX98090 Playback",
                .stream_name = "MAX98090 Playback",
                .cpu_dai_name = "DL1",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .codec_name = "snd-soc-dummy",
                .codec_dai_name = "snd-soc-dummy-dai",
                .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
@@ -114,7 +113,6 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = {
                .name = "MAX98090 Capture",
                .stream_name = "MAX98090 Capture",
                .cpu_dai_name = "VUL",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .codec_name = "snd-soc-dummy",
                .codec_dai_name = "snd-soc-dummy-dai",
                .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
@@ -125,7 +123,6 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = {
        {
                .name = "Codec",
                .cpu_dai_name = "I2S",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .no_pcm = 1,
                .codec_dai_name = "HiFi",
                .init = mt8173_max98090_init,
@@ -152,9 +149,21 @@ static struct snd_soc_card mt8173_max98090_card = {
 static int mt8173_max98090_dev_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &mt8173_max98090_card;
-       struct device_node *codec_node;
+       struct device_node *codec_node, *platform_node;
        int ret, i;
 
+       platform_node = of_parse_phandle(pdev->dev.of_node,
+                                        "mediatek,platform", 0);
+       if (!platform_node) {
+               dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+               return -EINVAL;
+       }
+       for (i = 0; i < card->num_links; i++) {
+               if (mt8173_max98090_dais[i].platform_name)
+                       continue;
+               mt8173_max98090_dais[i].platform_of_node = platform_node;
+       }
+
        codec_node = of_parse_phandle(pdev->dev.of_node,
                                      "mediatek,audio-codec", 0);
        if (!codec_node) {
index 0940553230596aed2ba41787b8605e26c2cc11c7..6f52eca05e2600f34c5b76deb77db81ab6fb9290 100644 (file)
@@ -138,7 +138,6 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
                .name = "rt5650_rt5676 Playback",
                .stream_name = "rt5650_rt5676 Playback",
                .cpu_dai_name = "DL1",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .codec_name = "snd-soc-dummy",
                .codec_dai_name = "snd-soc-dummy-dai",
                .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
@@ -149,7 +148,6 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
                .name = "rt5650_rt5676 Capture",
                .stream_name = "rt5650_rt5676 Capture",
                .cpu_dai_name = "VUL",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .codec_name = "snd-soc-dummy",
                .codec_dai_name = "snd-soc-dummy-dai",
                .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
@@ -161,7 +159,6 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
        {
                .name = "Codec",
                .cpu_dai_name = "I2S",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .no_pcm = 1,
                .codecs = mt8173_rt5650_rt5676_codecs,
                .num_codecs = 2,
@@ -209,7 +206,21 @@ static struct snd_soc_card mt8173_rt5650_rt5676_card = {
 static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &mt8173_rt5650_rt5676_card;
-       int ret;
+       struct device_node *platform_node;
+       int i, ret;
+
+       platform_node = of_parse_phandle(pdev->dev.of_node,
+                                        "mediatek,platform", 0);
+       if (!platform_node) {
+               dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < card->num_links; i++) {
+               if (mt8173_rt5650_rt5676_dais[i].platform_name)
+                       continue;
+               mt8173_rt5650_rt5676_dais[i].platform_of_node = platform_node;
+       }
 
        mt8173_rt5650_rt5676_codecs[0].of_node =
                of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);
index cc228db5fb760eaa24f98d91b0b14f0eded80ea9..9863da73dfe03a0f057d9897fd89e7d4d1614194 100644 (file)
@@ -1199,6 +1199,8 @@ err_pm_disable:
 static int mtk_afe_pcm_dev_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               mtk_afe_runtime_suspend(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
        return 0;
index 3a4a5c0e3f9737c795f74367b04c9825462651f8..0e1e69c7abd56b25fab6e4ffb0eab5fd574d03d2 100644 (file)
@@ -1716,6 +1716,7 @@ card_probe_error:
        if (card->remove)
                card->remove(card);
 
+       snd_soc_dapm_free(&card->dapm);
        soc_cleanup_card_debugfs(card);
        snd_card_free(card->snd_card);
 
index aa327c92480c56c2609699380594a75ad765fbda..e0de8072c5144e92fce3ec9518787a4db526d726 100644 (file)
@@ -358,9 +358,10 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
                        data->widget =
                                snd_soc_dapm_new_control_unlocked(widget->dapm,
                                &template);
+                       kfree(name);
                        if (!data->widget) {
                                ret = -ENOMEM;
-                               goto err_name;
+                               goto err_data;
                        }
                }
                break;
@@ -389,11 +390,12 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
 
                        data->value = template.on_val;
 
-                       data->widget = snd_soc_dapm_new_control(widget->dapm,
-                                       &template);
+                       data->widget = snd_soc_dapm_new_control_unlocked(
+                                               widget->dapm, &template);
+                       kfree(name);
                        if (!data->widget) {
                                ret = -ENOMEM;
-                               goto err_name;
+                               goto err_data;
                        }
 
                        snd_soc_dapm_add_path(widget->dapm, data->widget,
@@ -408,8 +410,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
 
        return 0;
 
-err_name:
-       kfree(name);
 err_data:
        kfree(data);
        return ret;
@@ -418,8 +418,6 @@ err_data:
 static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
 {
        struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
-       if (data->widget)
-               kfree(data->widget->name);
        kfree(data->wlist);
        kfree(data);
 }
@@ -1952,6 +1950,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
                                           size_t count, loff_t *ppos)
 {
        struct snd_soc_dapm_widget *w = file->private_data;
+       struct snd_soc_card *card = w->dapm->card;
        char *buf;
        int in, out;
        ssize_t ret;
@@ -1961,6 +1960,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&card->dapm_mutex);
+
        /* Supply widgets are not handled by is_connected_{input,output}_ep() */
        if (w->is_supply) {
                in = 0;
@@ -2007,6 +2008,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
                                        p->sink->name);
        }
 
+       mutex_unlock(&card->dapm_mutex);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
        kfree(buf);
@@ -2281,11 +2284,15 @@ static ssize_t dapm_widget_show(struct device *dev,
        struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
        int i, count = 0;
 
+       mutex_lock(&rtd->card->dapm_mutex);
+
        for (i = 0; i < rtd->num_codecs; i++) {
                struct snd_soc_codec *codec = rtd->codec_dais[i]->codec;
                count += dapm_widget_show_codec(codec, buf + count);
        }
 
+       mutex_unlock(&rtd->card->dapm_mutex);
+
        return count;
 }
 
@@ -3334,16 +3341,10 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
        }
 
        prefix = soc_dapm_prefix(dapm);
-       if (prefix) {
+       if (prefix)
                w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
-               if (widget->sname)
-                       w->sname = kasprintf(GFP_KERNEL, "%s %s", prefix,
-                                            widget->sname);
-       } else {
+       else
                w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
-               if (widget->sname)
-                       w->sname = kasprintf(GFP_KERNEL, "%s", widget->sname);
-       }
        if (w->name == NULL) {
                kfree(w);
                return NULL;
@@ -3792,7 +3793,7 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
                                break;
                        }
 
-                       if (!w->sname || !strstr(w->sname, dai_w->name))
+                       if (!w->sname || !strstr(w->sname, dai_w->sname))
                                continue;
 
                        if (dai_w->id == snd_soc_dapm_dai_in) {
index d0960683c4093c4303743b1e7e4f93190e11a3a5..31068b8f3db0dd965cc2bdc6742684dc2cb8d8ea 100644 (file)
@@ -33,6 +33,7 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/soc-topology.h>
+#include <sound/tlv.h>
 
 /*
  * We make several passes over the data (since it wont necessarily be ordered)
@@ -144,7 +145,7 @@ static const struct snd_soc_tplg_kcontrol_ops io_ops[] = {
        {SND_SOC_TPLG_CTL_STROBE, snd_soc_get_strobe,
                snd_soc_put_strobe, NULL},
        {SND_SOC_TPLG_DAPM_CTL_VOLSW, snd_soc_dapm_get_volsw,
-               snd_soc_dapm_put_volsw, NULL},
+               snd_soc_dapm_put_volsw, snd_soc_info_volsw},
        {SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE, snd_soc_dapm_get_enum_double,
                snd_soc_dapm_put_enum_double, snd_soc_info_enum_double},
        {SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT, snd_soc_dapm_get_enum_double,
@@ -534,7 +535,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
                        k->put = bops[i].put;
                if (k->get == NULL && bops[i].id == hdr->ops.get)
                        k->get = bops[i].get;
-               if (k->info == NULL && ops[i].id == hdr->ops.info)
+               if (k->info == NULL && bops[i].id == hdr->ops.info)
                        k->info = bops[i].info;
        }
 
@@ -579,29 +580,51 @@ static int soc_tplg_init_kcontrol(struct soc_tplg *tplg,
        return 0;
 }
 
+
+static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg,
+       struct snd_kcontrol_new *kc, struct snd_soc_tplg_tlv_dbscale *scale)
+{
+       unsigned int item_len = 2 * sizeof(unsigned int);
+       unsigned int *p;
+
+       p = kzalloc(item_len + 2 * sizeof(unsigned int), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+
+       p[0] = SNDRV_CTL_TLVT_DB_SCALE;
+       p[1] = item_len;
+       p[2] = scale->min;
+       p[3] = (scale->step & TLV_DB_SCALE_MASK)
+                       | (scale->mute ? TLV_DB_SCALE_MUTE : 0);
+
+       kc->tlv.p = (void *)p;
+       return 0;
+}
+
 static int soc_tplg_create_tlv(struct soc_tplg *tplg,
-       struct snd_kcontrol_new *kc, u32 tlv_size)
+       struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc)
 {
        struct snd_soc_tplg_ctl_tlv *tplg_tlv;
-       struct snd_ctl_tlv *tlv;
 
-       if (tlv_size == 0)
+       if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE))
                return 0;
 
-       tplg_tlv = (struct snd_soc_tplg_ctl_tlv *) tplg->pos;
-       tplg->pos += tlv_size;
-
-       tlv = kzalloc(sizeof(*tlv) + tlv_size, GFP_KERNEL);
-       if (tlv == NULL)
-               return -ENOMEM;
-
-       dev_dbg(tplg->dev, " created TLV type %d size %d bytes\n",
-               tplg_tlv->numid, tplg_tlv->size);
+       if (tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+               kc->tlv.c = snd_soc_bytes_tlv_callback;
+       } else {
+               tplg_tlv = &tc->tlv;
+               switch (tplg_tlv->type) {
+               case SNDRV_CTL_TLVT_DB_SCALE:
+                       return soc_tplg_create_tlv_db_scale(tplg, kc,
+                                       &tplg_tlv->scale);
 
-       tlv->numid = tplg_tlv->numid;
-       tlv->length = tplg_tlv->size;
-       memcpy(tlv->tlv, tplg_tlv + 1, tplg_tlv->size);
-       kc->tlv.p = (void *)tlv;
+               /* TODO: add support for other TLV types */
+               default:
+                       dev_dbg(tplg->dev, "Unsupported TLV type %d\n",
+                                       tplg_tlv->type);
+                       return -EINVAL;
+               }
+       }
 
        return 0;
 }
@@ -773,7 +796,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
                }
 
                /* create any TLV data */
-               soc_tplg_create_tlv(tplg, &kc, mc->hdr.tlv_size);
+               soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
 
                /* register control here */
                err = soc_tplg_add_kcontrol(tplg, &kc,
@@ -1351,6 +1374,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
        template.reg = w->reg;
        template.shift = w->shift;
        template.mask = w->mask;
+       template.subseq = w->subseq;
        template.on_val = w->invert ? 0 : 1;
        template.off_val = w->invert ? 1 : 0;
        template.ignore_suspend = w->ignore_suspend;
index 98d96e1b17e05847aaa2b48740f3f9f0cc2c6e2a..1930c42e1f557ae62c30003b379088f242b0dbfe 100644 (file)
@@ -393,9 +393,9 @@ static int zx_i2s_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        zx_i2s->mapbase = res->start;
        zx_i2s->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (!zx_i2s->reg_base) {
+       if (IS_ERR(zx_i2s->reg_base)) {
                dev_err(&pdev->dev, "ioremap failed!\n");
-               return -EIO;
+               return PTR_ERR(zx_i2s->reg_base);
        }
 
        writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL);
index 11a0e46a1156913a23d9f31852fa508cbd1f8c5f..26265ce4caca17da4b6315a4627130ac63851063 100644 (file)
@@ -322,9 +322,9 @@ static int zx_spdif_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        zx_spdif->mapbase = res->start;
        zx_spdif->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (!zx_spdif->reg_base) {
+       if (IS_ERR(zx_spdif->reg_base)) {
                dev_err(&pdev->dev, "ioremap failed!\n");
-               return -EIO;
+               return PTR_ERR(zx_spdif->reg_base);
        }
 
        zx_spdif_dev_init(zx_spdif->reg_base);
index 1b1a89e80d1394bb253aecc3cadc683dbcff3a36..784ceb85b2d9fe7cbe989d0c8443863f1d03df34 100644 (file)
@@ -956,6 +956,7 @@ static int snd_amd7930_create(struct snd_card *card,
        if (!amd->regs) {
                snd_printk(KERN_ERR
                           "amd7930-%d: Unable to map chip registers.\n", dev);
+               kfree(amd);
                return -EIO;
        }
 
index e5000da9e9d7093f6e287194665de2d63f046e93..6a803eff87f71110049d9c39cb07025d2c64d828 100644 (file)
@@ -341,6 +341,20 @@ static const struct usbmix_name_map scms_usb3318_map[] = {
        { 0 }
 };
 
+/* Bose companion 5, the dB conversion factor is 16 instead of 256 */
+static struct usbmix_dB_map bose_companion5_dB = {-5006, -6};
+static struct usbmix_name_map bose_companion5_map[] = {
+       { 3, NULL, .dB = &bose_companion5_dB },
+       { 0 }   /* terminator */
+};
+
+/* Dragonfly DAC 1.2, the dB conversion factor is 1 instead of 256 */
+static struct usbmix_dB_map dragonfly_1_2_dB = {0, 5000};
+static struct usbmix_name_map dragonfly_1_2_map[] = {
+       { 7, NULL, .dB = &dragonfly_1_2_dB },
+       { 0 }   /* terminator */
+};
+
 /*
  * Control map entries
  */
@@ -451,6 +465,16 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x25c4, 0x0003),
                .map = scms_usb3318_map,
        },
+       {
+               /* Bose Companion 5 */
+               .id = USB_ID(0x05a7, 0x1020),
+               .map = bose_companion5_map,
+       },
+       {
+               /* Dragonfly DAC 1.2 */
+               .id = USB_ID(0x21b4, 0x0081),
+               .map = dragonfly_1_2_map,
+       },
        { 0 } /* terminator */
 };
 
index 094ddaee104c73d7caae22d851d79629c4715cd3..d31fac19c30b2d298ab2cf3a710b9b27c5764144 100644 (file)
@@ -638,7 +638,7 @@ ifndef DESTDIR
 prefix ?= $(HOME)
 endif
 bindir_relative = bin
-bindir = $(prefix)/$(bindir_relative)
+bindir = $(abspath $(prefix)/$(bindir_relative))
 mandir = share/man
 infodir = share/info
 perfexecdir = libexec/perf-core
index 53e8bb7bc8521a09f1347d48de2a0dd1eeb5e0bc..2a5d8d7698aedb8c82bdf8488f1fb62ded5b438a 100644 (file)
@@ -85,7 +85,7 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
        else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
                update_stats(&runtime_cycles_stats[ctx][cpu], count[0]);
        else if (perf_stat_evsel__is(counter, CYCLES_IN_TX))
-               update_stats(&runtime_transaction_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_cycles_in_tx_stats[ctx][cpu], count[0]);
        else if (perf_stat_evsel__is(counter, TRANSACTION_START))
                update_stats(&runtime_transaction_stats[ctx][cpu], count[0]);
        else if (perf_stat_evsel__is(counter, ELISION_START))
@@ -398,20 +398,18 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
                                " #   %5.2f%% aborted cycles         ",
                                100.0 * ((total2-avg) / total));
        } else if (perf_stat_evsel__is(evsel, TRANSACTION_START) &&
-                  avg > 0 &&
                   runtime_cycles_in_tx_stats[ctx][cpu].n != 0) {
                total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
 
-               if (total)
+               if (avg)
                        ratio = total / avg;
 
                fprintf(out, " # %8.0f cycles / transaction   ", ratio);
        } else if (perf_stat_evsel__is(evsel, ELISION_START) &&
-                  avg > 0 &&
                   runtime_cycles_in_tx_stats[ctx][cpu].n != 0) {
                total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
 
-               if (total)
+               if (avg)
                        ratio = total / avg;
 
                fprintf(out, " # %8.0f cycles / elision       ", ratio);
index 7f0c756993af15a0b5cb99ba50dd6f7d0dfca226..3d7dc6afc3f8f9459ca407ee5a16b1b2c9a8119b 100644 (file)
@@ -191,7 +191,7 @@ int main(int argc, char *argv[])
                if (res > 0) {
                        atomic_set(&requeued, 1);
                        break;
-               } else if (res > 0) {
+               } else if (res < 0) {
                        error("FUTEX_CMP_REQUEUE_PI failed\n", errno);
                        ret = RET_ERROR;
                        break;